I have a background service running which sends out emails to users of my website. I would like to write the email templates as MVC views, to keep things consistent (so that the same model can be used to send out an email as to display a web page).
Unfortunately, when I try to do a LoadControl (which simply patches through to BuildManager.CreateInstanceFromVirtualPath), I get the following:
System.NullReferenceException at
System.Web.dll!System.Web.VirtualPath.GetCacheKey() + 0x26 bytes
System.Web.dll!System.Web.Compilation.BuildManager.GetCacheKeyFromVirtualPath + 0x2a bytes
System.Web.dll!System.Web.Compilation.BuildManager.GetVPathBuildResultFromCacheInternal + 0x30 bytes
It seems that if I were to set MvcBuildViews to true, that there should be some easy way to use the compiled views to build an email template, but I can't figure out how.
I found the following blog from Rick Strahl, which may do the trick: http://www.west-wind.com/presentations/aspnetruntime/aspnetruntime.asp
However, it seems to start up a whole ASP.NET server to process requests.
Is there a simple way to load an MVC view & render it? Or is the only way to load up the ASP.NET runtime as suggested by Rick Strahl?
The default asp.net view engine is tied to the asp.net engine. Its tied to the context, I think you can work around it but its definitely not simple.
The issue is with the default view engine + asp.net engine combination, other view engines shouldn't have that issue. At the very least the spark view engine doesn't.
Edit: OP solved with the last hints, but fwiw my version that uses the controller home index action of the default asp.net mvc project template:
public class MyAppHost : MarshalByRefObject
{
public string RenderHomeIndexAction()
{
var controller = new HomeController();
using (var writer = new StringWriter())
{
var httpContext = new HttpContext(new HttpRequest("", "http://example.com", ""), new HttpResponse(writer));
if (HttpContext.Current != null) throw new NotSupportedException("httpcontext was already set");
HttpContext.Current = httpContext;
var controllerName = controller.GetType().Name;
var routeData = new RouteData();
routeData.Values.Add("controller", controllerName.Remove(controllerName.LastIndexOf("Controller")));
routeData.Values.Add("action", "index");
var controllerContext = new ControllerContext(new HttpContextWrapper(httpContext), routeData, controller);
var res = controller.Index();
res.ExecuteResult(controllerContext);
HttpContext.Current = null;
return writer.ToString();
}
}
}
... from a separate project:
[TestMethod]
public void TestIndexAction()
{
var myAppHost = (MyAppHost)ApplicationHost.CreateApplicationHost(
typeof(MyAppHost), "/", @"c:\full\physical\path\to\the\mvc\project");
var view = myAppHost.RenderHomeIndexAction();
Assert.IsTrue(view.Contains("learn more about"));
}
Some extra notes:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With