将LoadControl与Object Initializer一起创建属性
-
21-09-2019 - |
题
过去,我使用USERCONTROL来创建电子邮件模板,我可以在上面填充属性,然后使用LoadControl,然后RenderControl来获取HTML,以用于我的电子邮件的正文文本。这在ASP.NET WebForms中。
我正在构建MVC网站,并想做类似的事情。实际上,我实际上考虑过将此功能放在单独的类库中,并正在研究如何做到这一点,以便在我的网层中,我可以调用emailtemplate.subscriptionemail(),然后从我的模板中生成HTML,并具有相关属性的属性地点(显然需要有电子邮件地址等参数)。
我想创建一个单个渲染控制方法,我可以将字符串传递到我的模板的UserControl路径。我在网络上遇到了适合我需求的网络:
public static string RenderUserControl(string path,
string propertyName, object propertyValue)
{
Page pageHolder = new Page();
UserControl viewControl =
(UserControl)pageHolder.LoadControl(path);
if (propertyValue != null)
{
Type viewControlType = viewControl.GetType();
PropertyInfo property = viewControlType.GetProperty(propertyName);
if (property != null)
property.SetValue(viewControl, propertyValue, null);
else
{
throw new Exception(string.Format(
"UserControl: {0} does not have a public {1} property.",
path, propertyName));
}
}
pageHolder.Controls.Add(viewControl);
StringWriter output = new StringWriter();
HttpContext.Current.Server.Execute(pageHolder, output, false);
return output.ToString();
}
我的问题是我的USERCONTROL可能具有多个且不同的属性。因此,订阅可能需要FirstName和EmailAddress,其中另一个电子邮件模板UserControl(我们称为DummyeMail)将需要FirstName,emailAddress和dateofbirth。
上面的方法似乎仅带有一个用于属性名称和属性值的参数。我考虑了一系列的字符串,我可以将不同的属性放入其中,但后来我认为拥有一个对象Intialiser会很酷,因此我可以称呼这样的方法:
RenderUserControl("EmailTemplates/SubscribeEmail.ascs", new object() { Firstname="Lloyd", Email="myemail@mydomain.com" })
那有意义吗?我只是想知道这是否首先是可能的,以及如何实施?我不确定是否可以将“对象”上设置的属性映射到已加载的用户控件上的属性以及是否可以从哪里开始?
有人做过这样的事情吗?谁能帮忙?
劳埃德
解决方案
您的示例可以实现。但这违反了MVC模式。而且,如果您要这样做,那么您也可以使用与WebForms完全相同的解决方案。
当我创建HTML邮件时,我通常会创建一个普通的MVC视图(在某些控制器和一个视图上采用操作)。然后,我将该视图渲染到字符串中并将其发送给。这样,您遵循MVC模式,并且可以自动看到邮件中的邮件(您只需访问该操作的URL。当然,这可以以任何您想要的方式受到限制)。
要渲染到字符串的视图,我使用此类:
public class ViewRenderer
{
protected RouteCollection RouteCollection { get; private set; }
public DefaultViewRenderer()
: this(RouteTable.Routes)
{
}
public DefaultViewRenderer(RouteCollection routeCollection)
{
RouteCollection = routeCollection;
}
public virtual string RenderViewAsString<TController>(Expression<Action<TController>> action)
where TController : Controller
{
var sb = new StringBuilder();
var memWriter = new StringWriter(sb);
var fakeContext = CreateFakeContext(memWriter);
var oldContext = HttpContext.Current;
HttpContext.Current = fakeContext;
CreateHtmlHelper(fakeContext).RenderAction(action);
HttpContext.Current = oldContext;
memWriter.Flush();
memWriter.Dispose();
return sb.ToString();
}
protected virtual HttpContext CreateFakeContext(StringWriter memWriter)
{
var fakeResponse = new HttpResponse(memWriter);
var context = new HttpContext(HttpContext.Current.Request, fakeResponse);
foreach (var key in HttpContext.Current.Items.Keys)
context.Items[key] = HttpContext.Current.Items[key];
foreach (string key in HttpContext.Current.Session.Keys)
context.Session[key] = HttpContext.Current.Session[key];
return context;
}
protected virtual HtmlHelper CreateHtmlHelper(HttpContext fakeContext)
{
var fakeControllerContext = CreateControllerContext(fakeContext, RouteCollection);
return new HtmlHelper(new ViewContext(fakeControllerContext,
new FakeView(), new ViewDataDictionary(), new TempDataDictionary()), new FakePage());
}
protected virtual ControllerContext CreateControllerContext(HttpContext fakeContext, RouteCollection routeCollection)
{
return new ControllerContext(
new HttpContextWrapper(fakeContext),
routeCollection.GetRouteData(new HttpContextWrapper(HttpContext.Current)), new FakeController());
}
protected class FakeView : IView
{
public void Render(ViewContext viewContext, TextWriter writer)
{
throw new NotImplementedException();
}
}
protected class FakeController : Controller
{
}
protected class FakePage : IViewDataContainer
{
public ViewDataDictionary ViewData
{
get { return new ViewDataDictionary(); }
set { }
}
}
}
这使用了将视图结果写入字符串构造器的假响应。然后,您以此为此:
var viewRenderer = new ViewRenderer();
var body = viewRenderer.RenderViewAsString<SomeController>(x => x.ActionThatRendersHtmlMail(parameters));
然后,您只需将邮件发送带有该正文文字即可。您当然可以将其包裹在自己的课堂中,以便可以致电emailTemplate.subscriptionEmail(); (从您的示例中)。