51 votes

Vues dans des assemblys distincts dans ASP.NET MVC

Je suis en train de créer une webapplication où je veux être en mesure de plug-in assemblées distinctes. Je suis en utilisant MVC aperçu 4 combiné avec l'Unité pour l'injection de dépendances, que j'utilise pour créer les contrôleurs de mon plugin assemblées. Je suis à l'aide de Formulaires web (par défaut aspx) que mon point de vue moteur.

Si je veux utiliser un point de vue, je suis bloqué sur ceux qui sont définis dans le projet de base, en raison de la dynamique de la compilation de la ASPX. Je suis à la recherche d'une bonne façon de joindre des fichiers ASPX dans un montage différent, sans avoir à passer par l'ensemble de l'étape de déploiement. Ai-je raté quelque chose d'évident? Ou devrais-je recourir à la création de mon point de vue par programmation?


Mise à jour: j'ai changé la accepté de répondre. Même si Dale réponse est très complète, j'ai opté pour la solution avec un autre chemin d'accès virtuel fournisseur. Il fonctionne comme un charme, et prend seulement environ 20 lignes de code au total, je pense.

30voto

Tom Clarkson Points 12369

Il m'a fallu beaucoup trop de temps à le faire fonctionner correctement à partir de différents échantillons partiels, donc voici le code complet nécessaire pour obtenir des vues à partir d'un dossier de Vues dans une bibliothèque partagée structuré de la même régulièrement des Vues sur le dossier, mais avec tout installé construire en tant que ressources intégrées. Il n'utilisera le fichier incorporé si le fichier habituel n'existe pas.

La première ligne de Application_Start:

HostingEnvironment.RegisterVirtualPathProvider(new EmbeddedViewPathProvider());

Le VirtualPathProvider

   public class EmbeddedVirtualFile : VirtualFile
{
    public EmbeddedVirtualFile(string virtualPath)
        : base(virtualPath)
    {
    }

    internal static string GetResourceName(string virtualPath)
    {
        if (!virtualPath.Contains("/Views/"))
        {
            return null;
        }



        var resourcename = virtualPath
            .Substring(virtualPath.IndexOf("Views/"))
            .Replace("Views/", "OrangeGuava.Common.Views.")
            .Replace("/", ".");

        return resourcename;

    }


    public override Stream Open()
    {
        Assembly assembly = Assembly.GetExecutingAssembly();


        var resourcename = GetResourceName(this.VirtualPath);
        return assembly.GetManifestResourceStream(resourcename);
    }




}

public class EmbeddedViewPathProvider : VirtualPathProvider
{


    private bool ResourceFileExists(string virtualPath)
    {

        Assembly assembly = Assembly.GetExecutingAssembly();


        var resourcename = EmbeddedVirtualFile.GetResourceName(virtualPath);
        var result = resourcename != null && assembly.GetManifestResourceNames().Contains(resourcename);
        return result;
    }

    public override bool FileExists(string virtualPath)
    {
        return base.FileExists(virtualPath) || ResourceFileExists(virtualPath);
    }


    public override VirtualFile GetFile(string virtualPath)
    {

        if (!base.FileExists(virtualPath))
        {
            return new EmbeddedVirtualFile(virtualPath);
        }
        else
        {
            return base.GetFile(virtualPath);
        }

    }

}

La dernière étape de ce travail est que la racine Web.Config doit contenir le droit de paramètres à analyser fortement typé MVC point de vue, comme celui dans le dossier vues ne sont pas utilisés:

<pages
    validateRequest="false"
    pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
    pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
    userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
  <controls>
    <add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" />
  </controls>
</pages>

Quelques étapes supplémentaires sont nécessaires pour le faire fonctionner avec Mono. Tout d'abord, vous avez besoin pour mettre en œuvre GetDirectory, puisque tous les fichiers dans le dossier vues chargés au démarrage de l'application plutôt qu'en tant que de besoin:

public override VirtualDirectory GetDirectory(string virtualDir)
    {
        Log.LogInfo("GetDirectory - " + virtualDir);
        var b = base.GetDirectory(virtualDir);
        return new EmbeddedVirtualDirectory(virtualDir, b);
    }

public class EmbeddedVirtualDirectory : VirtualDirectory
{
    private VirtualDirectory FileDir { get; set; } 

    public EmbeddedVirtualDirectory(string virtualPath, VirtualDirectory filedir)
        : base(virtualPath)
    {
        FileDir = filedir;
    }

    public override System.Collections.IEnumerable Children
    {
        get { return FileDir.Children; }
    }

    public override System.Collections.IEnumerable Directories
    {
        get { return FileDir.Directories; }
    }

    public override System.Collections.IEnumerable Files
    {
        get {

            if (!VirtualPath.Contains("/Views/") || VirtualPath.EndsWith("/Views/"))
            {
                return FileDir.Files;
            }

            var fl = new List<VirtualFile>();

            foreach (VirtualFile f in FileDir.Files)
            {
                fl.Add(f);
            }


            var resourcename = VirtualPath.Substring(VirtualPath.IndexOf("Views/"))
.Replace("Views/", "OrangeGuava.Common.Views.")
.Replace("/", ".");

            Assembly assembly = Assembly.GetExecutingAssembly();

            var rfl = assembly.GetManifestResourceNames()
                .Where(s => s.StartsWith(resourcename))
                .Select(s => VirtualPath + s.Replace(resourcename, ""))
                .Select(s => new EmbeddedVirtualFile(s));
            fl.AddRange(rfl);

            return fl;
        }
    }
}

Enfin, des points de vue fortement typée presque mais pas tout à fait le travail parfaitement. Le modèle sera traité comme un non objet, de sorte à obtenir un typage fort retour vous avez besoin pour commencer votre échangé des vues avec quelque chose comme

<% var Model2 = Model as IEnumerable<AppModel>;  %>

16voto

Joseph Kingry Points 4594

En gros, il s’agit du même problème que les utilisateurs de WebForm et qui tentaient de compiler leurs fichiers UserControl ASCX dans une DLL. J'ai trouvé ce http://www.codeproject.com/KB/aspnet/ASP2UserControlLibrary.aspx qui pourrait fonctionner pour vous aussi.

2voto

Erik van Brakel Points 7589

Un ajout à vous tous qui êtes toujours à la recherche du saint graal: j'ai parcouru un peu plus près à le trouver, si vous n'êtes pas trop attaché à l'webforms viewengine.

J'ai récemment essayé la Spark viewengine. Autre que d'être totalement génial et je ne voudrais pas revenir à webforms, même si j'ai été menacées, il fournit également quelques très belles crochets pour la modularité d'une application. L'exemple dans leurs docs est à l'aide de Windsor comme un conteneur IoC, mais je ne peux pas imaginer que ce soit beaucoup plus difficile si vous voulez prendre une autre approche. Lire ici.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X