Question

J'essaie de créer une application Web dans laquelle je souhaite pouvoir brancher des assemblys séparés.J'utilise MVC Preview 4 combiné avec Unity pour l'injection de dépendances, que j'utilise pour créer les contrôleurs à partir de mes assemblys de plugins.J'utilise WebForms (aspx par défaut) comme moteur d'affichage.

Si je veux utiliser une vue, je suis bloqué sur celles qui sont définies dans le projet principal, à cause de la compilation dynamique de la partie ASPX.Je recherche un moyen approprié de placer des fichiers ASPX dans un assembly différent, sans avoir à passer par toute l'étape de déploiement.Est-ce que j'ai raté quelque chose d'évident ?Ou devrais-je recourir à la création de mes vues par programme ?


Mise à jour:J'ai changé la réponse acceptée.Même si la réponse de Dale est très complète, j'ai opté pour la solution auprès d'un autre fournisseur de chemin virtuel.Cela fonctionne à merveille et ne prend qu'une vingtaine de lignes de code au total, je pense.

Était-ce utile?

La solution

Il s'agit essentiellement du même problème que celui rencontré par les utilisateurs avec WebForms et en essayant de compiler leurs fichiers UserControl ASCX dans une DLL.j'ai trouvé ça http://www.codeproject.com/KB/aspnet/ASP2UserControlLibrary.aspx cela pourrait fonctionner pour vous aussi.

Autres conseils

Il m'a fallu beaucoup trop de temps pour que cela fonctionne correctement à partir des différents exemples partiels. Voici donc le code complet nécessaire pour obtenir des vues à partir d'un dossier Views dans une bibliothèque partagée structurée de la même manière qu'un dossier Views standard, mais avec tout ce qui est configuré pour être intégré. ressources.Il n'utilisera le fichier embarqué que si le fichier habituel n'existe pas.

La première ligne de Application_Start :

HostingEnvironment.RegisterVirtualPathProvider(new EmbeddedViewPathProvider());

Le fournisseur de chemin virtuel

   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 pour le faire fonctionner est que le Web.Config racine doit contenir les bons paramètres pour analyser les vues MVC fortement typées, car celle du dossier vues ne sera pas utilisée :

<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 que cela fonctionne avec Mono.Tout d’abord, vous devez implémenter GetDirectory, car tous les fichiers du dossier vues sont chargés au démarrage de l’application plutôt qu’en cas 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, les vues fortement typées fonctionneront presque parfaitement, mais pas tout à fait.Le modèle sera traité comme un objet non typé, donc pour obtenir une saisie forte, vous devez commencer vos vues partagées avec quelque chose comme

<% var Model2 = Model as IEnumerable<AppModel>;  %>
protected void Application_Start()
{
    WebFormViewEngine engine = new WebFormViewEngine();

    engine.ViewLocationFormats = new[] { "~/bin/Views/{1}/{0}.aspx", "~/Views/Shared/{0}.aspx" };
    engine.PartialViewLocationFormats = engine.ViewLocationFormats;

    ViewEngines.Engines.Clear();
    ViewEngines.Engines.Add(engine);

    RegisterRoutes(RouteTable.Routes);
}

Définissez la propriété « Copier vers la sortie » de votre vue sur « Copier toujours »

Un ajout pour tous ceux qui recherchent encore le Saint Graal :Je suis un peu plus près de le trouver, si vous n'êtes pas trop attaché au moteur d'affichage des formulaires Web.

J'ai récemment essayé le moteur d'affichage Spark.En plus d'être totalement génial et que je ne reviendrais pas aux formulaires Web même si j'étais menacé, il fournit également de très bons crochets pour la modularité d'une application.L'exemple dans leur documentation utilise Windsor comme conteneur IoC, mais je ne peux pas imaginer que ce soit beaucoup plus difficile si vous souhaitez adopter une autre approche.

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