ASP.NET MVC 3 RC AreaRegistration.RegisterAllAreas()和动态加载的程序集

Rob*_*bin 13 asp.net-mvc asp.net-mvc-areas asp.net-mvc-3

我目前正在尝试使用ASP.NET MVC 3 RC动态加载区域.我已经看到它写在许多地方,这不是那些区域的目的,并且(至少预MVC 2)不可能,例如在这里说.

但是还是!它应该可以让它工作,对吧?我创建了一个解决方案,添加了一个MVC 3项目,添加了一个区域和一些内容.一切都运作良好.现在我创建了一个新的类库项目(在同一个解决方案中),从MVC项目添加了对它的引用,并开始将与区域相关的部分移动到库中.将库项目的输出目录更改为MVC项目的area-folder,并确保将Views及其web.config复制到output-folder.

在阅读了很多关于你如何不能拥有外部区域之后,这有点令人惊讶.真的没问题!当我删除项目之间的引用,而不是在代码中加载库时,问题就开始了.(在打电话之前AreaRegistration.RegisterAllAreas().)现在它不起作用.完全没有.

我一直在寻找MVC 3的源代码,问题似乎BuildManager.GetReferencedAssemblies()是用于让程序集寻找实现AreaRegistration.

现在,我不是百分之百地确定这一点,但似乎这个方法只查看在编译时存在/引用的程序集,有人可以确认这是否实际上是这样的?

我通过这个调试了,而且方法调用确实没有找到我在调用它之前加载的程序集.这可能是因为我可能错过的其他东西......有什么想法吗?

mar*_*ind 20

事情的运作方式有点复杂.

GetReferencedAssemblies包括引用的程序集,而不是加载的程 这包括:

  • 应用程序的web.config中引用的所有程序集(例如System.Web.Mvc)
  • 从web web.config继承的所有东西,包括类似的东西System,System.Web以及你不必自己添加的其他东西.(你可以看看这里的清单:) C:\Windows\Microsoft.Net\Framework\v4.0.30319\web.config.
    它还包含一个特殊*项目,其中:
  • 包括您网站bin文件夹中的所有内容

所以现在拿你的应用程序v1(一切都在一个应用程序中).一切正常,因为应用程序代码被编译到自动包含的bin文件夹中.此外,所有区域视图等都在应用程序本身中,因此可以访问它们.

现在在app v2(带有proj-to-proj引用自定义构建任务的不同项目,将视图复制到主应用程序中的正确位置)一切仍然有效,因为默认情况下proj-to-proj引用意味着类库二进制文件被复制到应用程序的bin文件夹中.因此,通过上述规则,区域代码仍然可以正确加载.您已将库的输出路径设置为主应用程序的"区域"文件夹中的某个位置这一事实实际上没有什么区别 - 您最终会得到两个二进制副本.

现在在app v3(没有proj-proj ref,手动加载区域库程序集)你的库程序集加载太晚了.在代码运行时,已引用的程序集已被锁定且无法再更改.

有一种方法来运行代码,并添加项目注册组件列表:您可以通过做AddReferencedAssembly哪种方法必须从调用PreApplicationStartMethodAttribute方法.

当然,您仍然需要处理如何管理视图文件.您当前设置它的方式与在主应用程序中拥有视图几乎相同(因为它们有效地被复制到正确的位置).


LeL*_*g37 6

1 - 将你的Mvc区域分成不同的Mvc项目,编译成他们自己的单独组件

2 - 将其添加到AssemblyInfo.cs类,以在加载应用程序时调用方法

[assembly: PreApplicationStartMethod(typeof(PluginAreaBootstrapper), "Init")]
Run Code Online (Sandbox Code Playgroud)

3 - 这是在加载过程中调用Init方法时的样子

public class PluginAreaBootstrapper
{
    public static readonly List<Assembly> PluginAssemblies = new List<Assembly>();

    public static List<string> PluginNames()
    {
        return PluginAssemblies.Select(
            pluginAssembly => pluginAssembly.GetName().Name)
            .ToList();
    }

    public static void Init()
    {
        var fullPluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Areas");

        foreach (var file in Directory.EnumerateFiles(fullPluginPath, "*Plugin*.dll"))
            PluginAssemblies.Add(Assembly.LoadFile(file));

        PluginAssemblies.ForEach(BuildManager.AddReferencedAssembly);
    }
}
Run Code Online (Sandbox Code Playgroud)

4 - 添加自定义RazorViewEngine

public class PluginRazorViewEngine : RazorViewEngine
{
    public PluginRazorViewEngine()
    {
        AreaMasterLocationFormats = new[]
        {
            "~/Areas/{2}/Views/{1}/{0}.cshtml",
            "~/Areas/{2}/Views/{1}/{0}.vbhtml",
            "~/Areas/{2}/Views/Shared/{0}.cshtml",
            "~/Areas/{2}/Views/Shared/{0}.vbhtml"
        };

        AreaPartialViewLocationFormats = new[]
        {
            "~/Areas/{2}/Views/{1}/{0}.cshtml",
            "~/Areas/{2}/Views/{1}/{0}.vbhtml",
            "~/Areas/{2}/Views/Shared/{0}.cshtml",
            "~/Areas/{2}/Views/Shared/{0}.vbhtml"
        };

        var areaViewAndPartialViewLocationFormats = new List<string>
        {
            "~/Areas/{2}/Views/{1}/{0}.cshtml",
            "~/Areas/{2}/Views/{1}/{0}.vbhtml",
            "~/Areas/{2}/Views/Shared/{0}.cshtml",
            "~/Areas/{2}/Views/Shared/{0}.vbhtml"
        };

        var partialViewLocationFormats = new List<string>
        {
            "~/Views/{1}/{0}.cshtml",
            "~/Views/{1}/{0}.vbhtml",
            "~/Views/Shared/{0}.cshtml",
            "~/Views/Shared/{0}.vbhtml"
        };

        var masterLocationFormats = new List<string>
        {
            "~/Views/{1}/{0}.cshtml",
            "~/Views/{1}/{0}.vbhtml",
            "~/Views/Shared/{0}.cshtml",
            "~/Views/Shared/{0}.vbhtml"
        };

        foreach (var plugin in PluginAreaBootstrapper.PluginNames())
        {
            masterLocationFormats.Add(
                "~/Areas/" + plugin + "/Views/{1}/{0}.cshtml");
            masterLocationFormats.Add(
                "~/Areas/" + plugin + "/Views/{1}/{0}.vbhtml");
            masterLocationFormats.Add(
                "~/Areas/" + plugin + "/Views/Shared/{1}/{0}.cshtml");
            masterLocationFormats.Add(
                "~/Areas/" + plugin + "/Views/Shared/{1}/{0}.vbhtml");

            partialViewLocationFormats.Add(
                "~/Areas/" + plugin + "/Views/{1}/{0}.cshtml");
            partialViewLocationFormats.Add(
                "~/Areas/" + plugin + "/Views/{1}/{0}.vbhtml");
            partialViewLocationFormats.Add(
                "~/Areas/" + plugin + "/Views/Shared/{0}.cshtml");
            partialViewLocationFormats.Add(
                "~/Areas/" + plugin + "/Views/Shared/{0}.vbhtml");

            areaViewAndPartialViewLocationFormats.Add(
                "~/Areas/" + plugin + "/Views/{1}/{0}.cshtml");
            areaViewAndPartialViewLocationFormats.Add(
                "~/Areas/" + plugin + "/Views/{1}/{0}.vbhtml");
            areaViewAndPartialViewLocationFormats.Add(
                "~/Areas/" + plugin + "/Areas/{2}/Views/{1}/{0}.cshtml");
            areaViewAndPartialViewLocationFormats.Add(
                "~/Areas/" + plugin + "/Areas/{2}/Views/{1}/{0}.vbhtml");
            areaViewAndPartialViewLocationFormats.Add(
                "~/Areas/" + plugin + "/Areas/{2}/Views/Shared/{0}.cshtml");
            areaViewAndPartialViewLocationFormats.Add(
                "~/Areas/" + plugin + "/Areas/{2}/Views/Shared/{0}.vbhtml");
        }

        ViewLocationFormats = partialViewLocationFormats.ToArray();
        MasterLocationFormats = masterLocationFormats.ToArray();
        PartialViewLocationFormats = partialViewLocationFormats.ToArray();
        AreaPartialViewLocationFormats = areaViewAndPartialViewLocationFormats.ToArray();
        AreaViewLocationFormats = areaViewAndPartialViewLocationFormats.ToArray();
    }
}
Run Code Online (Sandbox Code Playgroud)

5 - 从您的不同Mvc(区域)项目注册您的区域

namespace MvcApplication8.Web.MyPlugin1
{
    public class MyPlugin1AreaRegistration : AreaRegistration
    {
        public override string AreaName
        {
            get { return "MyPlugin1"; }
        }

        public override void RegisterArea(AreaRegistrationContext context)
        {
            context.MapRoute(
                "MyPlugin1_default",
                "MyPlugin1/{controller}/{action}/{id}",
                new {action = "Index", id = UrlParameter.Optional}
                );
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

源代码和其他参考资料可以在这里找到:http://blog.longle.io/2012/03/29/building-a-composite-mvc3-application-with-pluggable-areas