Frage

Ich versuche, eine Webanwendung zu erstellen, in die ich separate Assemblys einbinden möchte.Ich verwende MVC Preview 4 in Kombination mit Unity für die Abhängigkeitsinjektion, mit der ich die Controller aus meinen Plugin-Assemblys erstelle.Ich verwende WebForms (Standard-ASPX) als meine Ansichts-Engine.

Wenn ich eine Ansicht verwenden möchte, bleibe ich aufgrund der dynamischen Kompilierung des ASPX-Teils bei den Ansichten, die im Kernprojekt definiert sind.Ich suche nach einer geeigneten Möglichkeit, ASPX-Dateien in eine andere Assembly einzuschließen, ohne den gesamten Bereitstellungsschritt durchlaufen zu müssen.Übersehe ich etwas Offensichtliches?Oder sollte ich darauf zurückgreifen, meine Ansichten programmgesteuert zu erstellen?


Aktualisieren:Ich habe die akzeptierte Antwort geändert.Obwohl Dales Antwort sehr ausführlich ist, habe ich mich für die Lösung mit einem anderen Anbieter virtueller Pfade entschieden.Es funktioniert wie ein Zauber und benötigt meiner Meinung nach insgesamt nur etwa 20 Codezeilen.

War es hilfreich?

Lösung

Im Grunde handelt es sich dabei um das gleiche Problem, das Leute hatten, die mit WebForms versuchten, ihre UserControl-ASCX-Dateien in eine DLL zu kompilieren.ich habe das gefunden http://www.codeproject.com/KB/aspnet/ASP2UserControlLibrary.aspx das könnte auch für dich funktionieren.

Andere Tipps

Es hat viel zu lange gedauert, bis ich dies anhand der verschiedenen Teilbeispiele richtig zum Laufen gebracht habe. Hier ist also der vollständige Code, der benötigt wird, um Ansichten aus einem Views-Ordner in einer gemeinsam genutzten Bibliothek abzurufen, die genauso strukturiert ist wie ein normaler Views-Ordner, aber alles so eingestellt ist, dass es als eingebetteter Build erstellt wird Ressourcen.Die eingebettete Datei wird nur verwendet, wenn die übliche Datei nicht vorhanden ist.

Die erste Zeile von Application_Start:

HostingEnvironment.RegisterVirtualPathProvider(new EmbeddedViewPathProvider());

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

    }

}

Der letzte Schritt, damit es funktioniert, besteht darin, dass die Root-Web.Config die richtigen Einstellungen zum Parsen stark typisierter MVC-Ansichten enthalten muss, da die im Ansichtenordner nicht verwendet wird:

<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>

Damit es mit Mono funktioniert, sind ein paar zusätzliche Schritte erforderlich.Zuerst müssen Sie GetDirectory implementieren, da alle Dateien im Ordner „views“ beim Start der App geladen werden und nicht bei Bedarf:

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

Schließlich funktionieren stark typisierte Ansichten fast, aber nicht ganz perfekt.Das Modell wird als untypisiertes Objekt behandelt. Um also wieder eine starke Eingabe zu erhalten, müssen Sie Ihre freigegebenen Ansichten mit etwas wie beginnen

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

Setzen Sie die Eigenschaft „In Ausgabe kopieren“ Ihrer Ansicht auf „Immer kopieren“.

Eine Ergänzung für alle, die noch auf der Suche nach dem Heiligen Gral sind:Ich bin der Suche ein Stück näher gekommen, wenn Sie nicht zu sehr an die Webforms-Viewengine gebunden sind.

Ich habe kürzlich die Spark-Viewengine ausprobiert.Abgesehen davon, dass es absolut großartig ist und ich nicht zu Webformularen zurückkehren würde, selbst wenn ich bedroht würde, bietet es auch einige sehr nette Ansatzpunkte für die Modularität einer Anwendung.Das Beispiel in ihren Dokumenten verwendet Windsor als IoC-Container, aber ich kann mir nicht vorstellen, dass es viel schwieriger sein wird, wenn Sie einen anderen Ansatz wählen möchten.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top