Pregunta

Actualmente estoy experimentando con zonas de carga dinámica con ASP.NET MVC 3 RC. Lo he visto escrito en muchos lugares que esto no es lo que están destinados a áreas, y (al menos antes de la MVC 2) no es posible, dicen aquí por ejemplo.

Pero todavía! Debería ser posible para conseguir que el trabajo, ¿verdad? He creado una solución, añadido un proyecto MVC 3, añadido un área y algo de contenido. Todo está funcionando bien. Ahora he creado un nuevo proyecto de biblioteca de clases (en la misma solución), añadido una referencia a él desde el proyecto MVC, y comenzó a moverse sobre las partes relacionadas con la superficie a la biblioteca. Cambiado la salida-directorio del proyecto de la biblioteca a la zona carpeta del proyecto MVC, y se aseguró de las Vistas y su web.config se copian en la salida-carpeta.

Después de leer tanto sobre la forma en que no podría haber áreas externas, que era un poco sorprendente que esto funcionó. No hay ningún problema de verdad! El problema comienza cuando se quita la referencia entre los proyectos, y en lugar de cargar la biblioteca de código. (Antes de llamar AreaRegistration.RegisterAllAreas().) Ahora que no funciona. En absoluto.

he estado hurgando un poco en la fuente para MVC 3, y el problema parece estar relacionado con BuildManager.GetReferencedAssemblies() que se utiliza para obtener los montajes para tener en cuenta las implementaciones de AreaRegistration.

Ahora, no estoy 100% seguro de esto, pero parece como si este método sólo se ve en las asambleas que estaban presentes / referenciados en tiempo de compilación, alguien puede confirmar si esto es de hecho tan?

He depurado a través de este, y que el método de guardia de hecho no encuentra el conjunto cargué justo antes de la llamada al mismo. Podría ser debido a alguna otra cosa que me he perdido tal vez .. ¿Alguna idea?

¿Fue útil?

Solución

La forma en que funcionan las cosas es un poco complicado.

GetReferencedAssemblies incluye ensamblados de referencia, asambleas no cargados. Esto incluye:

  • todos los ensamblados de referencia en el que web.config de la aplicación (como System.Web.Mvc)
  • todo lo heredado de raíz web.config, que incluye cosas como System, System.Web y otros que usted no tiene que agregarse. (Puede echar un vistazo a la lista aquí: C:\Windows\Microsoft.Net\Framework\v4.0.30319\web.config).
    También contiene un elemento * especial, que
  • incluye todo en su sitio bin de carpeta

Así que ahora tomar su aplicación v1 (todo en una sola aplicación). Todo funciona debido a que el código de la aplicación se compila en la carpeta bin que obtiene automáticamente incluido. Además, todas las vistas de la zona, etc se encuentran en la propia aplicación para que sean accesibles.

Ahora en aplicación v2 (proyecto diferente con una referencia-proj-a proj y una tarea de generación personalizada que copia las visitas a la ubicación correcta en su aplicación principal) todo sigue funcionando, ya que por defecto a referencias medios-proj-proj a que el binario biblioteca de clases se copia en la carpeta bin de su aplicación. Así que por las reglas anteriores, el código de área todavía se carga correctamente. El hecho de que ha configurado la ruta de salida de la biblioteca para ser algún lugar dentro de las áreas de su aplicación principal de la carpeta no hace realmente una diferencia -. Que acaba de terminar con dos copias del binario

Ahora en v3 aplicación (sin proj proj-ref, biblioteca zona de montaje cargado manualmente) la biblioteca de ensamblaje se carga demasiado tarde. En el momento en que su código se ejecuta el conjunto de ensamblados de referencia ya ha sido bloqueado y ya no se puede cambiar.

Hay una manera de ejecutar código y añadir elementos a la lista de ensamblados registrados: puede hacerlo utilizando el AddReferencedAssembly método que debe ser invocado desde un método PreApplicationStartMethodAttribute .

Por supuesto, usted todavía tiene que lidiar con la forma de administrar sus archivos de vista. La forma en que actualmente tienes configurado es más o menos lo mismo que tener las vistas de la aplicación principal (ya que efectivamente se copia en la ubicación correcta).

Otros consejos

1 - Separa le Áreas MVC en proyectos MVC differrent a ser compilado en sus propias asambleas separadas

2 - Añadir esto a su clase AssemblyInfo.cs, para llamar a un método cuando se carga la aplicación

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

3 - Esto es lo que las miradas método Init como cuando se invoca durante la carga

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 - Añadir una RazorViewEngine personalizada

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 - Registro de sus áreas diferentes de su MVC (Zona) Proyectos

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

El código fuente y referencias adicionales se puede encontrar aquí: http://blog.longle.io/2012/03/29/building-a-composite-mvc3-application-with-pluggable-areas

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top