想法
我正在尝试构建模块化的.NET Core MVC应用程序,只要将所需的库复制到预定义的文件夹中即可添加“模块”(扩展名)。该应用程序定义了一组依赖项(DI),错误处理和基本布局。这些模块提供了实际的应用程序或页面逻辑。
我们使用ExtCore构建了概念验证-这个概念很好用,控制器被自动添加并且可以轻松识别“纯视图”(设置为“嵌入式资源”的视图)。
挑战
但是,我不喜欢将Views设置为“ Embedded Resource”的事实,因为Razor页面现在是在运行时生成的,因此对性能的影响不大。
我们尝试过的事情
由于.NET Core 2.1现在具有创建Reusable Razor UI的能力,因此我创建了一个引用<Project Sdk="Microsoft.NET.Sdk.Razor">
的项目,并将其编译到Razor库(* .Views.dll)中。
当我在主应用程序中将Razor View库链接为项目依赖项时,一切正常。但是,目标仍然是使应用程序完全即插即用,并允许仅通过将库部署到文件夹中就可以包含库。
我尝试使用PhysicalFileProvider
扩展Razor View Engine,但它无法识别库中的视图。
services.Configure<RazorViewEngineOptions>(opt =>
{
opt.FileProviders.Add(new PhysicalFileProvider("path/to/extension"));
});
结果始终是一个异常,告诉我找不到/Views/[controller]/[action].cshtml
。
搜索其他遇到的问题,我遇到了一个this项目,该项目创建了一个ViewLocationExpander
。我尝试实现此想法的各种版本时都没有碰到运气-很有可能是因为这是基于.NET Core 1.x的较旧概念,仍然使用项目依赖项。尽管Razor View引擎现在可以搜索程序集的名称空间。
services.Configure<RazorViewEngineOptions>(opt =>
{
opt.FileProviders.Add(new PhysicalFileProvider("path/to/extension");
opt.ViewLocationExpanders.Add(new DynamicLocationExpander());
});
DynamicLocationExpander
如下所示:
public class DynamicLocationExpander: IViewLocationExpander
{
public DynamicLocationExpander()
{
}
public void PopulateValues(ViewLocationExpanderContext context)
{
}
public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
{
string assembly = ((ControllerActionDescriptor)context.ActionContext.ActionDescriptor)
.ControllerTypeInfo.AsType().Assembly.GetName().Name;
foreach (var viewLocation in viewLocations)
yield return $"{assembly}/{viewLocation}";
}
}
问题
我们如何动态地将包含预编译视图的Razor View库链接到(父)应用程序中的Razor Engine?