ASP.NET MVC 3 RC AreaRegistration.RegisterAllAreas() and dynamically loaded assemblies

前端 未结 2 444
难免孤独
难免孤独 2020-12-24 15:16

I am currently experimenting with dynamically loaded areas with ASP.NET MVC 3 RC. I\'ve seen it written in many places that this is not what areas are intended for, and (at

相关标签:
2条回答
  • 2020-12-24 16:00

    1 - Seperate you Mvc Areas into differrent Mvc Projects to be compiled into their own seperate assemblies

    2 - Add this to your AssemblyInfo.cs class, to call a method when the application is loaded

    [assembly: PreApplicationStartMethod(typeof(PluginAreaBootstrapper), "Init")]
    

    3 - Here's what the Init method looks like when it's invoked during the load

    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);
        }
    }
    

    4 - Add a custom 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();
        }
    }
    

    5 - Register your Areas from your different Mvc (Area) Projects

    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}
                    );
            }
        }
    }
    

    Sourcecode and additional references can can be found here:http://blog.longle.io/2012/03/29/building-a-composite-mvc3-application-with-pluggable-areas

    0 讨论(0)
  • 2020-12-24 16:21

    The way things work is a bit complicated.

    GetReferencedAssemblies includes referenced assemblies, not loaded assemblies. This includes:

    • all assemblies referenced in you application's web.config (such as System.Web.Mvc)
    • everything inherited from root web.config, which includes things like System, System.Web and others that you do not have to add yourself. (You can take a look at the list here: C:\Windows\Microsoft.Net\Framework\v4.0.30319\web.config).
      It also contains a special * item, which:
    • includes everything in your site's bin folder

    So now take your app v1 (everything in a single app). Everything works because the application code gets compiled into the bin folder which gets automatically included. Also, all of the area views etc are in the application itself so they are accessible.

    Now in app v2 (different project with a proj-to-proj reference and a custom build task that copies the views to the right location in your main app) everything still works, because by default a proj-to-proj references means that the class library binary gets copied to your app's bin folder. So by the above rules, the area code still gets loaded correctly. The fact that you've set the library's output path to be some location within your main app's Areas folder does not actually make a difference - you just end up with two copies of the binary.

    Now in app v3 (no proj-proj ref, area library assembly loaded manually) your library assembly gets loaded too late. By the time your code runs the set of referenced assemblies has already been locked and can no longer be changed.

    There is a way to run code and add items to the list of registered assemblies: you can do it using the AddReferencedAssembly method which must be invoked from a PreApplicationStartMethodAttribute method.

    Of course you still have to deal with how you manage your view files. The way you currently have it set up is pretty much the same as having the views in the main application (since they effectively get copied into the right location).

    0 讨论(0)
提交回复
热议问题