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);
}
这并获得成功。我们基本上强制PrecompiledMvcEngine“忘记”我们在具体项目中的任何视图。
您也可以从RazorGenerator.Mvc 2.1.0尝试CompositePrecompiledMvcEngine。它被设计用于正确支持多个程序集中的视图重写。的码片:
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)的视图,它将保持源映射不变。