有没有办法从非Web应用程序处理MVC视图(aspx文件)?

我有一个后台服务运行,它向我的网站用户发送电子邮件。 我想将电子邮件模板编写为MVC视图,以保持一致(以便可以使用相同的模型发送电子邮件以显示网页)。

不幸的是,当我尝试执行LoadControl(只是修补到BuildManager.CreateInstanceFromVirtualPath)时,我得到以下内容:

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 

似乎如果我将MvcBuildViews设置为true,那么应该有一些简单的方法来使用编译的视图来构建电子邮件模板,但我无法弄清楚如何。

我从Rick Strahl找到了以下博客,可能会有这样的伎俩: http : //www.west-wind.com/presentations/aspnetruntime/aspnetruntime.asp

但是,它似乎启动了一个完整的ASP.NET服务器来处理请求。

有没有一种简单的方法来加载MVC视图并渲染它? 或者是Rick Strahl建议的加载ASP.NET运行时的唯一方法?

默认的asp.net视图引擎与asp.net引擎绑定。 它与上下文联系在一起,我认为你可以解决它,但它绝对不简单

问题在于默认的视图引擎+ asp.net引擎组合,其他视图引擎不应该有这个问题。 至少火花视图引擎没有。


编辑: OP解决了最后的提示,但fwiw我的版本使用默认的asp.net mvc项目模板的控制器主页索引操作:

 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(); } } } 

……来自一个单独的项目:

  [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")); } 

一些额外的说明:

  • 新的HttpRequest中的url无关紧要,但需要是一个有效的url
  • 它并不意味着从已经有上下文的asp.net应用程序中使用,或者说,我不确定它是否实际上产生了新的AppDomain并且工作
  • 控制器类型的构造函数和特定实例在代码中是显式的,可以替换为在参数中传递的东西,但需要处理MarshalByRef /最坏情况的限制,可以使用一些简单的reflection来实现它

结束回答我自己的问题:)

 public class AspHost : MarshalByRefObject { public string _VirtualDir; public string _PhysicalDir; public string ViewToString(string aspx, Dictionary viewData, T model) { StringBuilder sb = new StringBuilder(); using (StringWriter sw = new StringWriter(sb)) { using (HtmlTextWriter tw = new HtmlTextWriter(sw)) { var workerRequest = new SimpleWorkerRequest(aspx, "", tw); HttpContext.Current = new HttpContext(workerRequest); ViewDataDictionary viewDataDictionary = new ViewDataDictionary(model); foreach (KeyValuePair pair in viewData) { viewDataDictionary.Add(pair.Key, pair.Value); } object view = BuildManager.CreateInstanceFromVirtualPath(aspx, typeof(object)); ViewPage viewPage = view as ViewPage; if (viewPage != null) { viewPage.ViewData = viewDataDictionary; } else { ViewUserControl viewUserControl = view as ViewUserControl; if (viewUserControl != null) { viewPage = new ViewPage(); viewPage.Controls.Add(viewUserControl); } } if (viewPage != null) { HttpContext.Current.Server.Execute(viewPage, tw, true); return sb.ToString(); } throw new InvalidOperationException(); } } } public static AspHost SetupFakeHttpContext(string physicalDir, string virtualDir) { return (AspHost)ApplicationHost.CreateApplicationHost( typeof(AspHost), virtualDir, physicalDir); } } 

然后,渲染文件:

 var host = AspHost.SetupFakeHttpContext("Path/To/Your/MvcApplication", "/"); var viewData = new ViewDataDictionary(){ Model = myModel }; String rendered = host.ViewToString("~/Views/MyView.aspx", new Dictionary(viewData), viewData.Model); 

总之,没有 – ASP.NET视图呈现与Web响应周期结合在一起。 在过去,获得合理的表现可能是非常必要的。

现在,还存在一些其他选项,包括Microsoft的新剃刀视图引擎或开源Spark View引擎 。

我们在Web应用程序离线时使用了Cassini Web服务器。 可能这种方法对你也有用吗? 看看卡西尼

这是我的第一次尝试,但失败了。 请参阅上面的正确和有效的答案

这是我能够得到的尽可能接近,但它仍然无法正常工作。 现在它抱怨get_Server导致NullreferenceException。

我以为我会在这里发布我做了什么以及我有多远,以防有人想继续研究。

我修改了我的csproj文件以生成带有预编译ASPX文件的程序集,如下所示:

  ... true C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\NETFX 4.0 Tools\aspnet_merge.exe ...       

这创建了一个“MyProject_CompiledAspx.dll”,然后我从我的应用程序中引用了它。 但是,这会导致新的NullReferenceException。

ASPX文件虽然function强大,却与ASP.NET服务器紧密集成,这是一个很小的问题。