Question

Je suis en train d'expérimenter avec des zones chargées dynamiquement avec ASP.NET MVC 3 RC. Je l'ai vu écrit dans de nombreux endroits que ce n'est pas quels domaines sont destinés, et (au moins pré-MVC 2) pas possible, par exemple par exemple.

Mais encore! Il devrait être possible de le faire au travail, droit? J'ai créé une solution, a ajouté un projet MVC 3, a ajouté une zone et un contenu. Tout fonctionne bien. Maintenant, je créé un nouveau projet de bibliothèque de classes (dans la même solution), a ajouté une référence à celle du MVC-projet, et commencé à se déplacer sur les parties liées à la région à la bibliothèque. Modification de la sortie-répertoire du projet de bibliothèque dans la zone-dossier du projet MVC, et fait en sorte que les vues et leurs web.config sont copiés sur la sortie-dossier.

Après avoir lu tant de choses sur la façon dont vous ne pourriez pas avoir des zones extérieures, il était un peu surprenant que cela a fonctionné. Pas de problème du tout vraiment! Le problème commence lorsque je retire la référence entre les projets et la charge à la place de la bibliothèque dans le code. (Avant d'appeler AreaRegistration.RegisterAllAreas().) Maintenant, il ne fonctionne pas. A tout.

J'ai été farfouillé un peu dans la source pour MVC 3, et le problème semble être avec BuildManager.GetReferencedAssemblies() qui est utilisé pour obtenir les ensembles à regarder pour les implémentations de AreaRegistration.

Maintenant, je ne suis pas sûr à 100%, mais il semble que cette méthode ne porte que sur des ensembles qui étaient présents / référencés à la compilation, quelqu'un peut-il confirmer si cela est en fait donc?

Je déboguée par là, et que la méthode d'appel ne fait pas trouver l'ensemble je charge juste avant l'appel à elle. Il est peut-être à cause de quelque chose d'autre que je l'ai peut-être manqué .. Des idées?

Était-ce utile?

La solution

Les travaux de façon dont les choses est un peu compliqué.

GetReferencedAssemblies comprend des ensembles référencés, ensembles ne sont pas chargées. Cela comprend:

  • tous les ensembles référencés en vous web.config de l'application (par exemple System.Web.Mvc)
  • tout hérité de web.config racine, ce qui inclut des choses comme System, System.Web et d'autres que vous n'avez pas à vous-même ajouter. (Vous pouvez jeter un oeil à la liste ici: C:\Windows\Microsoft.Net\Framework\v4.0.30319\web.config).
    Il contient également un élément spécial * qui :
  • comprend tout dans le dossier de votre site de bin

Alors maintenant, prenez votre application v1 (tout dans une seule application). Tout fonctionne parce que le code de l'application est compilée dans le dossier bin qui obtient automatiquement inclus. En outre, toutes les vues de la région, etc sont dans l'application elle-même si elles sont accessibles.

dans l'application v2 (autre projet avec une référence proj-à-proj et une tâche de construction personnalisée qui copie les vues au bon endroit dans votre application principale) tout fonctionne encore, car par défaut une des références proj-à-proj signifie que le binaire de bibliothèque de classes est copié dans le dossier bin de votre application. Ainsi, les règles ci-dessus, le code de la zone obtient toujours correctement chargé. Le fait que vous avez défini le chemin de sortie de la bibliothèque pour être un emplacement au sein de votre principale zones d'application dossier ne fait pas vraiment une différence -. Vous venez de finir avec deux copies du binaire

dans l'application v3 (pas ref proj-proj, bibliothèque zone assemblage chargée manuellement) votre bibliothèque assemblage se charge trop tard. Au moment où votre code exécute l'ensemble des assemblages référencés a déjà été verrouillé et ne peut plus être modifié.

Il existe un moyen d'exécuter du code et ajouter des éléments à la liste des ensembles enregistrés: vous pouvez le faire en utilisant le AddReferencedAssembly qui doit être invoqué à partir d'un méthode de PreApplicationStartMethodAttribute .

Bien sûr, vous avez encore à faire face à la façon dont vous gérez vos fichiers de vue. La façon dont vous avez actuellement mis en place, il est à peu près la même chose que d'avoir le point de vue dans l'application principale (car ils sont copiés dans le bon endroit efficacement).

Autres conseils

1 - Seperate vous dans les zones Mvc projets differrent Mvc à compiler dans leurs propres assemblées séparées

2 - Ajouter à votre classe AssemblyInfo.cs, appeler une méthode lorsque l'application est chargée

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

3 - Voici ce que la méthode Init ressemble quand il est invoqué au cours de la charge

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 - Ajouter un RazorViewEngine personnalisé

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 - Enregistrez vos zones de vos différents Mvc (Région) Projets

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

Le code source et les références supplémentaires peuvent être trouvés ici: http://blog.longle.io/2012/03/29/building-a-composite-mvc3-application-with-pluggable-areas

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top