如何将来自外部项目的控制器和视图包含到 MVC6 中?

How to include controllers and views from an external project into MVC6?

我有一些模块有控制器和视图。它基本上是我的网络应用程序的扩展。每个模块都在 class 库中。

我想从我的 Web 应用程序加载这些程序集。但是我在这里运气不好。


我的解决方案文件结构如下:

src
|
|-- Web.Common  (Class Library Project)
|   |- Files like: filters, my own controller etc...
|    
|-- WebApplication (ASP.NET5 WebSite)
|   |- wwwroot
|   |- Controllers
|   |- Views
|   |- etc...
|
|-- Module 1 (Class Library Project)
|   |- Controllers
|   |- Views
|
|-- Module 2 etc...

这些是我尝试过的:


我尝试实现自己的 IViewLocationExpander

public class CustomViewLocationExpander : IViewLocationExpander
{
    public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
    {
        yield return "/../Module1.Web/Views/Home/TestView.cshtml";
        yield return "../Module1.Web/Views/Home/TestView.cshtml";
        yield return "/Module1.Web/Views/Home/TestView.cshtml";
        yield return "~/../Module1.Web/Views/Home/TestView.cshtml";
    }

    public void PopulateValues(ViewLocationExpanderContext context)
    {

    }
}

我尝试了所有想到的路径,但没有成功:(

我得到:

InvalidOperationException: The view 'TestView' was not found. The following locations were searched:

~/Module1.Web/Views/Home/TestView.cshtml ~/../Module1.Web/Views/Home/TestView.cshtml /Module1.Web/Views/Home/TestView.cshtml /../Module1.Web/Views/Home/TestView.cshtml


所以我认为默认的 IFileProvider 可能不会查看 WebApp 的根路径之外,因此决定尝试实现我自己的 IFileProvider。

但是在这里我也没有成功。


也许有一个功能可以通过调用一些 ASP.NET 方法来实现,但我不知道。

有什么建议吗?

我认为视图必须存在于主 Web 应用程序中 unless you want to use some non-standard 3rd party solutions

我的理解是,在 beta7 中,我们将能够在使用 VS 2015 构建 class 库时创建的 class 库 nuget 中打包视图和其他内容文件。但是我的理解是当主网络应用程序添加对这样一个 nuget 的依赖时,内容文件将被添加到主网络应用程序,即我的视图将被添加到 Views/MyModule 或类似的东西下面,以便它们可以从主要网络应用程序。

至少这是我希望采取的方法,这样我的观点就可以被其他人阅读and/or 修改。

我认为另一种选择是预编译视图,使它们不作为 .cshtml 文件存在于磁盘上,但这会使其他人更难自定义视图。

我通过使用 IViewLocationExpanderPhysicalFileProvider

实现了这一点

我使用剃须刀引擎的 IFileProvider 将根路径设置为 src 文件夹。通过附加程序集名称,我得到了项目根路径的路径。

public class MultiAssemblyViewLocationExpander : IViewLocationExpander
{
    public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
    {
        var actionContext = (ResultExecutingContext)context.ActionContext;
        var assembly = actionContext.Controller.GetType().Assembly;
        var assemblyName = assembly.GetName().Name;

        foreach (var viewLocation in viewLocations)
            yield return "/" + assemblyName + viewLocation;
    }

    public void PopulateValues(ViewLocationExpanderContext context)
    {

    }
}

并且在 ConfigureServices 方法中:

services.Configure<RazorViewEngineOptions>(options =>
{
    options.FileProvider = new PhysicalFileProvider(HostingEnvironment.WebRootPath + "..\..\");
    options.ViewLocationExpanders.Add(new MultiAssemblyViewLocationExpander ());
});

PS:我没有在已发布的应用程序上对此进行测试。但如果出现一些路径问题,修复它会很容易;)

控制器将自动加载。要加载视图,您需要 EmbeddedFileProviderCompositeFileProvider,它们都是新的,因此您需要从 aspnetvnext 提要中获取它们。

在您的启动 MVC6 项目中引用它们 project.json:

"Microsoft.AspNet.FileProviders.Composite": "1.0.0-*",
"Microsoft.AspNet.FileProviders.Embedded": "1.0.0-*",

更新您在 Startup.cs 中的服务注册:

    services.Configure<RazorViewEngineOptions>(options =>
    {
        options.FileProvider = new CompositeFileProvider(
            new EmbeddedFileProvider(
                typeof(BooksController).GetTypeInfo().Assembly,
                "BookStore.Portal" // your external assembly's base namespace
            ),
            options.FileProvider
        );
    });

在外部程序集的 project.json 中,添加:

  "resource": "Views/**"

这是一个示例实现,您可以克隆它并 运行 实际查看它: https://github.com/johnnyoshika/mvc6-view-components