2011-10-11 134 views
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。

回答

1

有標誌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

2

我寫了一個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「忘記」我們在具體項目中的任何視圖。

2

您也可以從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)的視圖,它將保持源映射不變。