Domanda

Attualmente sto sperimentando con le zone caricate dinamicamente con ASP.NET MVC 3 RC. L'ho visto scritto in molti luoghi che questo non è ciò che le aree sono destinate, e (almeno pre-MVC 2) non è possibile, dicono qui per esempio.

Ma ancora! Dovrebbe essere possibile per farlo funzionare, giusto? Ho creato una soluzione, aggiunto un 3 progetto MVC, ha aggiunto una zona e alcuni contenuti. Tutto sta funzionando bene. Ora ho creato un nuovo progetto di libreria di classi (nella stessa soluzione), aggiunto un riferimento ad esso dal MVC-progetto e cominciato a muoversi sopra le parti alla biblioteca per superficie. Cambiato l'uscita-directory del progetto biblioteca per l'area cartella del MVC-progetto e fatto in modo che le viste e la loro web.config vengono copiati nella cartella di output.

Dopo aver letto tanto di come non si potrebbe avere aree esterne, è stato un po 'sorprendente che questo ha funzionato. Nessun problema a tutti davvero! Il problema inizia quando rimuovo il riferimento tra i progetti, e invece caricare la libreria nel codice. (Prima di chiamare AreaRegistration.RegisterAllAreas()). Ora non funziona. A tutti.

Sono stato rovistando un po 'nel sorgente per MVC 3, e il problema sembra essere con BuildManager.GetReferencedAssemblies() che viene utilizzato per ottenere le assemblee per cercare implementazioni di AreaRegistration.

Ora, io non sono al 100% sicuro di questo, ma sembra come se questo metodo guarda solo alle assemblee che erano presenti / fa riferimento al momento della compilazione, qualcuno può confermare se questo è in realtà così?

Ho il debug attraverso questo, e che il metodo di guardia non effettivamente trovare il montaggio ho caricato appena prima della chiamata a esso. Potrebbe essere a causa di qualcos'altro che ho perso forse .. Tutte le idee?

È stato utile?

Soluzione

Il lavoro come le cose è un po 'complicato.

GetReferencedAssemblies assiemaggio riferimento, assiemi non caricati. Questo comprende:

  • tutti gli assembly a cui fa riferimento si web.config dell'applicazione (come System.Web.Mvc)
  • tutto ereditato da web.config root, che comprende le cose come System, System.Web e altri che non c'è bisogno di aggiungere se stessi. (Potete dare un'occhiata alla lista qui: C:\Windows\Microsoft.Net\Framework\v4.0.30319\web.config).
    Esso contiene anche una speciale voce di *, che :
  • include tutto in bin del tuo sito cartella

Così ora prendere la v1 app (tutto in una singola applicazione). Tutto funziona perché il codice dell'applicazione viene compilato nella cartella bin che viene automaticamente incluso. Inoltre, tutti i punti di vista dell'area, ecc sono nella stessa applicazione in modo che siano accessibili.

Ora in App v2 (progetto diverso con un riferimento proj-to-proj e un compito di generazione personalizzata che copia i punti di vista per la posizione giusta nella vostra applicazione principale) tutto funziona ancora, perché per impostazione predefinita un proj-to-proj riferimenti mezzi che il binario libreria di classi viene copiato nella cartella bin della vostra applicazione. Quindi, secondo le regole di cui sopra, il prefisso viene comunque caricata correttamente. Il fatto che tu hai impostato percorso di uscita della libreria da una certa posizione all'interno delle aree della tua app principale cartella in realtà non fa differenza -. Si finisce con due copie del binario

Ora in App v3 (senza prog-proj ref, biblioteca area di assemblaggio caricati manualmente) la libreria di montaggio viene caricato troppo tardi. Con il tempo il vostro codice viene eseguito l'insieme di assembly referenziati è già stato bloccato e non può più essere modificata.

C'è un modo per eseguire il codice e aggiungere elementi alla lista delle assemblee registrati: è possibile farlo utilizzando il AddReferencedAssembly metodo che em <> deve essere invocato da un metodo PreApplicationStartMethodAttribute .

Naturalmente si hanno ancora a che fare con il modo di gestire i file di visualizzazione. Il modo in cui si dispone attualmente di esso istituito è praticamente lo stesso di avere il punto di vista del ricorso principale (dal momento che effettivamente vengono copiati nella posizione giusta).

Altri suggerimenti

1 - Separare voi MVC Aree in differrent MVC Progetti per essere compilato nelle proprie assemblee separate

2 - Aggiungi questo alla classe AssemblyInfo.cs, di chiamare un metodo in cui viene caricata l'applicazione

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

3 - Ecco cosa il metodo init sembra quando viene invocato durante il carico

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 - Aggiungi un RazorViewEngine personalizzato

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 - Registrare i Aree dal diverso MVC (Area) Progetti

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 e ulteriori riferimenti può può essere trovato qui: http://blog.longle.io/2012/03/29/building-a-composite-mvc3-application-with-pluggable-areas

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top