【问题标题】:ASP.NET MVC 3.0 Razor, load View from anywhere out of the box?ASP.NET MVC 3.0 Razor,开箱即用地从任何地方加载视图?
【发布时间】:2011-06-11 12:26:56
【问题描述】:

真的可以从任何地方加载 View,而无需 在 MVC 3.0 中实现自定义VirtualPathProvider

如果是真的怎么办?

实现自定义VirtualPathProvider 基本上没有问题,它会加载 从任何地方查看,但我的实现只能在 MVC 2.0 中工作,而不能在 MVC 3.0 中工作,由于某种原因,方法 GetFile newer 调用了 MVC 3.0 中不存在的视图,在这种情况下,我得到“Server Error in '/' Application.

我从这里为我的自定义 VirtualPathProvider 遵循相同的代码:http://buildstarted.com/2010/09/28/mvc-3-razor-view-engine-without-a-controller/

更新 1

好的,在我将自定义 VirtualPathProvider 提供程序的注册放在 Application_Start() 的第一行之后,我确实解决了我的自定义 VirtualPathProvider 的问题

    protected void Application_Start()
    {
        //Should be first line before routes and areas registration.
        HostingEnvironment.RegisterVirtualPathProvider(new MyVirtualPathProvider());

        AreaRegistration.RegisterAllAreas();

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);
    }

AreaRegistration.RegisterAllAreas();RegisterRoutes(RouteTable.Routes); 方法override VirtualFile GetFile(string virtualPath) 之后在Global.asax.cs 中注册自定义VirtualPathProvider 时,方法override VirtualFile GetFile(string virtualPath) 将不适用于“虚拟视图”。

更新 2

这是否意味着RazorViewRazorViewEngineRender 类是答案?

更新 3

如果我的 razor 视图的字符串表示在文件系统中不存在(例如,我将 razor 视图存储在数据库中)我如何使用这种方法来渲染它http://buildstarted.com/2010/09/28/mvc-3-razor-view-engine-without-a-controller/

例如,我的视图的字符串表示如下:

"@{
    ViewBag.Title = ""About Us"";
}

<h2>About</h2>
<p>
     Put content here.
</p>"

更新 4

现在我明白了,为了能够使用@Html.&lt;something&gt;,应该实现自定义 TemplateBase。 HtmlTemplateBase&lt;T&gt; 的实现示例可以在这里找到http://www.fidelitydesign.net/?p=239,但它不适用于 RazorEngine v2,我成功编译了模板,然后在程序集加载方法 public override void Execute() 后将不会执行我得到一个错误:方法或操作未实现(stacktrace:http://tinypic.com/r/dcow4/7

为了让“public override T Model”发生,我确实在“public abstract class TemplateBase: TemplateBase, ITemplate”中将“public TModel Model”的声明更改为“public virtual TModel Model”。可能还有一些其他的改变应该做吗?或者HtmlTemplateBase&lt;T&gt; 中的某些内容应该以其他方式完成?

【问题讨论】:

标签: asp.net-mvc-3 razor


【解决方案1】:

不要被 Ben (@BuildStarted) 文章中的示例代码所迷惑。他正在详细介绍如何使用 Razor ViewEngine 的早期版本来呈现模板,而无需使用控制器操作。其目的是能够以通用方式呈现模板,而不是作为特定的页面视图。 (这就是我们的 RazorEngine 模板框架 @http://razorengine.codeplex.com)。

VirtualPathProvider 仍然是 ASP.NET 的核心部分。关于 MVC 3 的 DependencyResolver 替代 VirtualPathProvider 似乎存在普遍的混淆,但事实并非如此,您仍然需要提供者能够访问虚拟路径上的内容(顺便说一下,所有路径在ASP.NET 是虚拟的)。

还原我原来的答案,您应该能够纯粹通过继承 RazorViewEngine 并使用它来创建您的视图来实现您想要的。

看看这个话题:http://coderjournal.com/2009/05/creating-your-first-mvc-viewengine/

【讨论】:

    【解决方案2】:

    不,默认情况下不支持从数据库加载视图。你需要自己写VirtualPathProvider

    请注意,Ben 的博文实际上并没有直接解决您要解决的问题。以下博客文章看起来更接近您想要的内容:http://rebuildall.umbraworks.net/2009/11/17/ASP_NET_MVC_and_virtual_views。请注意,您是否尝试在数据库中存储 razor 或 aspx 视图并不重要。 Asp.Net 中的虚拟路径提供程序只是将路径映射到字节流,这些字节流是由该路径表示的文件的内容。

    【讨论】:

    • 好的,但是如果你把我的问题读到最后,我描述了一些细节/问题,我的提供者无法使用 MVC 3.0。
    【解决方案3】:

    我在为嵌入式资源视图实现 VirtualPathProvider 时遇到了类似的问题。解决方案是实现 GetFolder 和 GetFile。当您请求该视图时,视图引擎不仅仅调用 GetFile。在第一次请求时,它会查看 views 文件夹以查找所有可用视图。如果该调用未在列表中包含您的数据库视图,则在您尝试加载它们时将找不到它们。

    【讨论】:

      【解决方案4】:

      每个人都是正确的。我的帖子不是如何加载 Razor 作为替代品,而是作为一种在不使用 MVC 的情况下调用 razor 的方法。现在...你想要的很可能与我在How to Download Razor View Engine 的帖子有关,我在这里展示了如何创建自己的 ViewEngine 来托管剃须刀页面。它使用 @Matthew Abbott 和我用于 RazorEngine 的相同引擎 - 您可以从 CodePlex 获得。不幸的是,它并不完整,但它应该让你知道如何去做。 (我也会在这里发)

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Web;
      using System.Web.Mvc;
      using System.Web.Hosting;
      using System.IO;
      using System.Text.RegularExpressions;
      using System.Xml.Linq;
      
      namespace RazorViewEngine {
          /// <summary>
          /// ViewEngine for the RazorView. Provides basic file handling to load views. 
          /// </summary>
          public class RazorViewEngine : IViewEngine {
      
              string[] SearchLocations { get; set; }
              Tuple<string, string, RazorView> Cache { get; set; }
              VirtualPathProvider VirtualPathProvider { get; set; }
      
              public RazorViewEngine() {
                  //{1} == Controller name
                  //{0} == View name
                  SearchLocations = new string[] {
                      "~/Views/{1}/{0}.cshtml",
                      "~/Views/Shared/{0}.cshtml",
                  };
      
                  VirtualPathProvider = HostingEnvironment.VirtualPathProvider;
              }
      
              #region IViewEngine Members
      
              public ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache) {
                  return CreateView(controllerContext, partialViewName, null, null, useCache);
              }
      
              public ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) {
                  return CreateView(controllerContext, viewName, masterName, GetLayoutPath(controllerContext), useCache);
              }
      
              /// <summary>
              /// Meat of the FindView methods.
              /// </summary>
              /// <param name="controllerContext">The current controller context for this request.</param>
              /// <param name="viewName">The requested view name. </param>
              /// <param name="masterName">The master page view name (currently unused)</param>
              /// <param name="layoutPath">The layout path location (Replaces the masterpage in other view engines)</param>
              /// <param name="useCache">Cache the viewpage?</param>
              /// <remarks>The layout path is currently hardcoded to "Layout" and will look in the SearchLocations for that path</remarks>
              /// <returns>Returns a ViewEngineResult with the requested view</returns>
              public ViewEngineResult CreateView(ControllerContext controllerContext, string viewName, string masterName, string layoutPath, bool useCache) {
                  //grab the current controller from the route data
                  string controllerName = controllerContext.RouteData.GetRequiredString("controller");
      
                  //for proper error handling we need to return a list of locations we attempted to search for the view
                  string[] SearchedLocations;
      
                  //get the actual path of the view - returns null if none is found
                  string viewPath = GetViewPath(viewName, controllerName, out SearchedLocations);
      
                  if (viewPath != null) {
                      RazorView view = new RazorView(this, controllerContext, viewPath, layoutPath);
                      return new ViewEngineResult(view, this);
                  }
      
                  //we couldn't find the view - return an array of all locations we've looked in
                  return new ViewEngineResult(SearchedLocations);
              }
      
              /// <summary>
              /// Look for the view in the current file system
              /// </summary>
              /// <param name="viewName">The name of the View you're looking for</param>
              /// <param name="controllerName">Current controller name</param>
              /// <param name="SearchedLocations">out a list of locations searched</param>
              /// <returns>A string value of the relative path</returns>
              public string GetViewPath(string viewName, string controllerName, out string[] SearchedLocations) {
                  return FindPath(viewName, controllerName, out SearchedLocations);
              }
      
              /// <summary>
              /// Look for the view in the current file system
              /// </summary>
              /// <param name="viewName">The name of the View you're looking for</param>
              /// <param name="controllerName">Current controller name</param>
              /// <param name="SearchedLocations">out a list of locations searched</param>
              /// <returns>A string value of the relative path</returns>
              public string FindPath(string viewName, string controllerName, out string[] SearchedLocations) {
                  SearchedLocations = new string[SearchLocations.Length];
      
                  for (int i = 0; i < SearchLocations.Length; i++) {
                      string virtualPath = string.Format(SearchLocations[i], viewName, controllerName);
      
                      SearchedLocations[i] = virtualPath;
      
                      //check the active VirtualPathProvider if the file exists
                      if (VirtualPathProvider.FileExists(virtualPath)) {
                          //add it to cache - not currently implemented
                          return VirtualPathProvider.GetFile(virtualPath).VirtualPath;
                      }
                  }
      
                  return null;
              }
      
              /// <summary>
              /// Get the layout virtual path
              /// </summary>
              /// <param name="controllerContext">The current Controller context for this request</param>
              /// <returns>A string virtual path</returns>
              public string GetLayoutPath(ControllerContext controllerContext) {
                  //This should probably be added to a list of locations - I'm not sure exactly
                  //what I need to do with this yet.
                  string[] locations;
      
                  return FindPath("Layout", controllerContext.RouteData.GetRequiredString("controller"), out locations);
              }
      
              /// <summary>
              /// Current irrelevant
              /// </summary>
              /// <param name="controllerContext">The active controller context</param>
              /// <param name="view">View to release</param>
              public void ReleaseView(ControllerContext controllerContext, IView view) {
                  IDisposable disposable = view as IDisposable;
                  if (disposable != null) {
                      disposable.Dispose();
                  }
              }
      
              #endregion
          }
      
          /// <summary>
          /// Implements IView and renders a Razor
          /// </summary>
          public class RazorView : IView {
      
              ControllerContext ControllerContext;
              string ViewPath;
              string LayoutPath;
              RazorViewEngine Engine;
      
              public RazorView(RazorViewEngine engine, ControllerContext controllerContext, string viewPath, string layoutPath) {
                  //load the file
                  this.ControllerContext = controllerContext;
                  this.ViewPath = viewPath;
                  this.LayoutPath = layoutPath;
                  this.Engine = engine;
              }
      
              #region IView Members
      
              /// <summary>
              /// Converts Razor to html and writes it to the passed in writer
              /// </summary>
              /// <param name="viewContext"></param>
              /// <param name="writer"></param>
              public void Render(ViewContext viewContext, System.IO.TextWriter writer) {
                  //View contents
                  string contents = new StreamReader(VirtualPathProvider.OpenFile(ViewPath)).ReadToEnd();
                  string layoutContents = LayoutPath == null
                      ? null
                      : new StreamReader(VirtualPathProvider.OpenFile(LayoutPath)).ReadToEnd();
      
                  contents = Parse(contents);
      
                  string output;
                  output = contents;
      
                  writer.Write(output);
              }
      
              /// <summary>
              /// Converts Razor to html
              /// </summary>
              /// <param name="Razor">Razor text</param>
              /// <returns>Html formatted Razor text</returns>
              string Parse(string Razor) {
      
                  //Where do I get the model From
      
                  return RazorEngine.Razor.Parse(Razor);
              }
      
              #endregion
          }
      
      }
      

      【讨论】:

      • @BuildStarted Reading 更新@Matthew Abbott 回答我认为我需要做类似的事情,谢谢所有细节。
      • 首先我所做的是添加自定义引擎(您的实现),在运行我的 MVC 3.0 Web 应用程序后,我收到一个错误无法编译模板。检查错误列表以获取详细信息。然后我发现我使用的是未更新版本的 RazorEngine 然后在我下载 v 2.0 后我得到了同样的错误。我也读过这个线程razorengine.codeplex.com/Thread/View.aspx?ThreadId=235751,我在我的应用程序中引用了 Microsoft.CSharp 和 System.Core,并且 System.Web.Razor.dll 我将 true 设置为 Copy Local。不会编译的模板只是默认的MVC3.0 Home/Index View。
      • 比我引用 RazorEngine 作为一个项目来介入...这里是 printscrin,其中包含有关错误tinypic.com/r/rlx8cj/7 的更多详细信息,而且我在结果中发现了这个错误。错误:CompiledAssembly = 'results. CompiledAssembly' 引发了“System.IO.FileNotFoundException”类型的异常,它是否与完全信任有关?
      • 即将推出支持中等信任度的新版本的 RazorEngine - 如果这是您的问题。虽然基于例外它看起来不像。
      • 是的,因为我们的 Razor Engine 和 MVC 提供的不一样,所以你没有任何 MVC razor 引擎的功能。如果您想复制所有功能,则需要开发自己的 TemplateBase - 此时您不妨使用真正的 Razor Parser
      猜你喜欢
      • 1970-01-01
      • 2011-12-03
      • 1970-01-01
      • 1970-01-01
      • 2011-07-18
      • 2011-08-21
      • 1970-01-01
      • 2018-04-08
      • 2011-03-11
      相关资源
      最近更新 更多