2剃刀局部视图在不同项目中使用剃刀生成器

问题描述:

在我们的项目中,我们使用的是razorgenerator of David Ebbo。这使我们可以将我们的一些cshtml文件移动到类库中。2剃刀局部视图在不同项目中使用剃刀生成器

我们想什么,现在实现的是以下几点:

  • MyCommonViews具有“MyView.cshtml”在浏览文件夹。
  • MyWebProject在其Views文件夹中也有一个“MyView.cshtml”。
  • MyOtherWebProject在它的Views文件夹中没有“MyView.cshtml”。

当MyOtherWebProject需要加载MyView.cshtml时,它将选择编译MyCommonViews项目中的一个。这就是我们想要的。
但是当MyWebProject需要加载MyView.cshtml时,我们希望它获取MyWebProject本身中的“重写”MyView.cshtml文件。

是我们想要的吗?

Manu。

有标志PreemptPhysicalFiles = false这是神奇的。

全样本:

[assembly: WebActivator.PostApplicationStartMethod(typeof(Application.Web.Common.App_Start.RazorGeneratorMvcStart), "Start")] 

namespace Application.Web.Common.App_Start 
{ 
    public static class RazorGeneratorMvcStart 
    { 
     public static void Start() 
     { 
      var engine = new PrecompiledMvcEngine2(typeof (RazorGeneratorMvcStart).Assembly) 
          { 
           UsePhysicalViewsIfNewer = true, //compile if file changed 
           PreemptPhysicalFiles = false //use local file if exist 
          }; 

      ViewEngines.Engines.Add(engine);//Insert(0,engine) ignores local partial views 

      // StartPage lookups are done by WebPages. 
      VirtualPathFactoryManager.RegisterVirtualPathFactory(engine); 
     } 
    } 
} 

但是,有可能是小bug: http://razorgenerator.codeplex.com/workitem/100

我写了一个hacky解决方案为我们的问题。它入侵razorgenerators的viewengine,并从(私人只读)Dictionary中删除所有适当的条目。
代码在应用程序启动时运行。

谈话是便宜的,告诉我的代码:

private static void HackRazorGeneratorToAllowViewOverriding() 
    { 
     // first we search for the PrecompiledMvcEngine 
     var razorGeneratorViewEngine = ViewEngines.Engines.ToList().FirstOrDefault(ve => ve.GetType().Name.Contains("PrecompiledMvcEngine")); 
     if (razorGeneratorViewEngine == null) 
      return; 

     // retrieve the dictionary where it keeps the mapping between a view path and the (view object) type to instantiate 
     var razorMappings = (IDictionary<string, Type>)ReflectionUtils.GetPrivateReadonly("_mappings", razorGeneratorViewEngine); 

     // retrieve a list of all our cshtml files in our 'concrete' web project 
     var files = Directory.GetFiles(Path.Combine(WebConfigSettings.RootPath, "Views"), "*.cshtml", SearchOption.AllDirectories); 

     // do some kungfu on those file paths so that they are in the same format as in the razor mapping dictionary 
     var concreteViewPaths = files.Select(fp => string.Format("~{0}", fp.Replace(WebConfigSettings.RootPath, "").Replace(@"\", "/"))).ToList(); 

     // loop through each of the cshtml paths (of our 'concrete' project) and remove it from the razor mappings if it's there 
     concreteViewPaths.ForEach(vp => 
             { 
              if (razorMappings.ContainsKey(vp)) 
               razorMappings.Remove(vp); 
             }); 
    } 

WebConfigSettings.RootPath包含我们的Web应用程序的根目录HD的路径。

这是我们的静态ReflectionUtils类的一部分:

/// <summary> 
/// Get a field that is 'private readonly'. 
/// </summary> 
public static object GetPrivateReadonly(string readonlyPropName, object instance) 
{ 
    var field = instance.GetType().GetField(readonlyPropName, BindingFlags.Instance | BindingFlags.NonPublic); 
    if (field == null) 
     throw new NullReferenceException(string.Format("private readonly field '{0}' not found in '{1}'", readonlyPropName, instance)); 
    return field.GetValue(instance); 
} 

这并获得成功。我们基本上强制PrecompiledMvc​​Engine“忘记”我们在具体项目中的任何视图。

您也可以从RazorGenerator.Mvc 2.1.0尝试CompositePrecompiledMvc​​Engine。它被设计用于正确支持多个程序集中的视图重写。的码片:

var engine = new CompositePrecompiledMvcEngine(
/*1*/ PrecompiledViewAssembly.OfType<MyCommonViewsSomeClass>(), 
/*2*/ PrecompiledViewAssembly.OfType<MyWebProjectSomeClass>(
     usePhysicalViewsIfNewer: HttpContext.Current.IsDebuggingEnabled)); 

ViewEngines.Engines.Insert(0, engine); 
VirtualPathFactoryManager.RegisterVirtualPathFactory(engine); 

第一行寄存器从MyCommonViews组件(〜/查看/ MyView.cshtml)的所有视图中,第二线将寄存器从MyWebProject或MyOtherWebProject组件的所有视图。

当它遇到已注册的虚拟路径(MyWebProject程序集中的〜/ Views/MyView.cshtml)时,它将覆盖具有新视图类型映射的旧映射。

如果另一个项目没有具有相同虚拟路径(MyOtherWebProject)的视图,它将保持源映射不变。