C# ASP.NET MVC 中单独程序集中的视图

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19746/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-01 09:03:36  来源:igfitidea点击:

Views in separate assemblies in ASP.NET MVC

提问by Erik van Brakel

I'm trying to create a webapplication where I want to be able to plug-in separate assemblies. I'm using MVC preview 4 combined with Unity for dependency injection, which I use to create the controllers from my plugin assemblies. I'm using WebForms (default aspx) as my view engine.

我正在尝试创建一个 web 应用程序,我希望能够在其中插入单独的程序集。我正在使用 MVC 预览 4 结合 Unity 进行依赖注入,我用它来从我的插件程序集创建控制器。我使用 WebForms(默认 aspx)作为我的视图引擎。

If I want to use a view, I'm stuck on the ones that are defined in the core project, because of the dynamic compiling of the ASPX part. I'm looking for a proper way to enclose ASPX files in a different assembly, without having to go through the whole deployment step. Am I missing something obvious? Or should I resort to creating my views programmatically?

如果我想使用视图,我被困在核心项目中定义的那些,因为ASPX部分的动态编译。我正在寻找一种将 ASPX 文件包含在不同程序集中的正确方法,而无需完成整个部署步骤。我错过了一些明显的东西吗?或者我应该诉诸于以编程方式创建我的视图?



Update: I changed the accepted answer. Even though Dale's answer is very thorough, I went for the solution with a different virtual path provider. It works like a charm, and takes only about 20 lines in code altogether I think.

更新:我改变了接受的答案。尽管 Dale 的回答非常彻底,但我还是选择了不同的虚拟路径提供者的解决方案。它就像一个魅力,我认为总共只需要大约 20 行代码。

采纳答案by Joseph Kingry

Essentially this is the same issue as people had with WebForms and trying to compile their UserControl ASCX files into a DLL. I found this http://www.codeproject.com/KB/aspnet/ASP2UserControlLibrary.aspxthat might work for you too.

本质上,这与人们在使用 WebForms 并试图将他们的 UserControl ASCX 文件编译成 DLL 时遇到的问题相同。我发现这个http://www.codeproject.com/KB/aspnet/ASP2UserControlLibrary.aspx也可能对你有用。

回答by Joseph Kingry

protected void Application_Start()
{
    WebFormViewEngine engine = new WebFormViewEngine();

    engine.ViewLocationFormats = new[] { "~/bin/Views/{1}/{0}.aspx", "~/Views/Shared/{0}.aspx" };
    engine.PartialViewLocationFormats = engine.ViewLocationFormats;

    ViewEngines.Engines.Clear();
    ViewEngines.Engines.Add(engine);

    RegisterRoutes(RouteTable.Routes);
}

Set the 'Copy to output' property of your view to 'Copy always'

将视图的“复制到输出”属性设置为“始终复制”

回答by Erik van Brakel

An addition to all you who are still looking for the holy grail: I've come a bit closer to finding it, if you're not too attached to the webforms viewengine.

对所有仍在寻找圣杯的人的补充:如果您不太喜欢 webforms 视图引擎,我离找到它更近了一点。

I've recently tried out the Spark viewengine. Other than being totally awesome and I wouldn't go back to webforms even if I was threathened, it also provides some very nice hooks for modularity of an application. The example in their docs is using Windsor as an IoC container, but I can't imagine it to be a lot harder if you want to take another approach.

我最近尝试了 Spark 视图引擎。除了非常棒而且即使我受到威胁我也不会回到 webforms 之外,它还为应用程序的模块化提供了一些非常好的钩子。他们文档中的示例使用 Windsor 作为 IoC 容器,但如果您想采用另一种方法,我无法想象它会更难。

回答by Tom Clarkson

It took me way too long to get this working properly from the various partial samples, so here's the full code needed to get views from a Views folder in a shared library structured the same as a regular Views folder but with everything set to build as embedded resources. It will only use the embedded file if the usual file does not exist.

我花了很长时间才能从各种部分示例中正常工作,所以这里是从共享库中的 Views 文件夹中获取视图所需的完整代码,其结构与常规 Views 文件夹相同,但所有内容都设置为嵌入资源。如果通常的文件不存在,它只会使用嵌入的文件。

The first line of Application_Start:

Application_Start 的第一行:

HostingEnvironment.RegisterVirtualPathProvider(new EmbeddedViewPathProvider());

The VirtualPathProvider

VirtualPathProvider

   public class EmbeddedVirtualFile : VirtualFile
{
    public EmbeddedVirtualFile(string virtualPath)
        : base(virtualPath)
    {
    }

    internal static string GetResourceName(string virtualPath)
    {
        if (!virtualPath.Contains("/Views/"))
        {
            return null;
        }



        var resourcename = virtualPath
            .Substring(virtualPath.IndexOf("Views/"))
            .Replace("Views/", "OrangeGuava.Common.Views.")
            .Replace("/", ".");

        return resourcename;

    }


    public override Stream Open()
    {
        Assembly assembly = Assembly.GetExecutingAssembly();


        var resourcename = GetResourceName(this.VirtualPath);
        return assembly.GetManifestResourceStream(resourcename);
    }




}

public class EmbeddedViewPathProvider : VirtualPathProvider
{


    private bool ResourceFileExists(string virtualPath)
    {

        Assembly assembly = Assembly.GetExecutingAssembly();


        var resourcename = EmbeddedVirtualFile.GetResourceName(virtualPath);
        var result = resourcename != null && assembly.GetManifestResourceNames().Contains(resourcename);
        return result;
    }

    public override bool FileExists(string virtualPath)
    {
        return base.FileExists(virtualPath) || ResourceFileExists(virtualPath);
    }


    public override VirtualFile GetFile(string virtualPath)
    {

        if (!base.FileExists(virtualPath))
        {
            return new EmbeddedVirtualFile(virtualPath);
        }
        else
        {
            return base.GetFile(virtualPath);
        }

    }

}

The final step to get it working is that the root Web.Config must contain the right settings to parse strongly typed MVC views, as the one in the views folder won't be used:

让它工作的最后一步是根 Web.Config 必须包含正确的设置来解析强类型的 MVC 视图,因为将不会使用 views 文件夹中的那个:

<pages
    validateRequest="false"
    pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
    pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
    userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
  <controls>
    <add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" />
  </controls>
</pages>

A couple of additional steps are required to get it working with Mono. First, you need to implement GetDirectory, since all files in the views folder get loaded when the app starts rather than as needed:

需要几个额外的步骤才能让它与 Mono 一起工作。首先,您需要实现 GetDirectory,因为视图文件夹中的所有文件都是在应用程序启动时而不是根据需要加载的:

public override VirtualDirectory GetDirectory(string virtualDir)
    {
        Log.LogInfo("GetDirectory - " + virtualDir);
        var b = base.GetDirectory(virtualDir);
        return new EmbeddedVirtualDirectory(virtualDir, b);
    }

public class EmbeddedVirtualDirectory : VirtualDirectory
{
    private VirtualDirectory FileDir { get; set; } 

    public EmbeddedVirtualDirectory(string virtualPath, VirtualDirectory filedir)
        : base(virtualPath)
    {
        FileDir = filedir;
    }

    public override System.Collections.IEnumerable Children
    {
        get { return FileDir.Children; }
    }

    public override System.Collections.IEnumerable Directories
    {
        get { return FileDir.Directories; }
    }

    public override System.Collections.IEnumerable Files
    {
        get {

            if (!VirtualPath.Contains("/Views/") || VirtualPath.EndsWith("/Views/"))
            {
                return FileDir.Files;
            }

            var fl = new List<VirtualFile>();

            foreach (VirtualFile f in FileDir.Files)
            {
                fl.Add(f);
            }


            var resourcename = VirtualPath.Substring(VirtualPath.IndexOf("Views/"))
.Replace("Views/", "OrangeGuava.Common.Views.")
.Replace("/", ".");

            Assembly assembly = Assembly.GetExecutingAssembly();

            var rfl = assembly.GetManifestResourceNames()
                .Where(s => s.StartsWith(resourcename))
                .Select(s => VirtualPath + s.Replace(resourcename, ""))
                .Select(s => new EmbeddedVirtualFile(s));
            fl.AddRange(rfl);

            return fl;
        }
    }
}

Finally, strongly typed views will almost but not quite work perfectly. Model will be treated as an untyped object, so to get strong typing back you need to start your shared views with something like

最后,强类型视图几乎但不是很完美。模型将被视为无类型对象,因此要恢复强类型,您需要使用类似的内容启动共享视图

<% var Model2 = Model as IEnumerable<AppModel>;  %>