2015-12-03 19 views
14

Wenn ich meine Vorlage ohne das EditHistory-Element rende, funktioniert das. Wenn ich jedoch dieses zusätzliche Mitglied hinzufüge, das sich in meiner Anwendung befindet, erhalte ich eine Ausnahme Could not load file or assembly 'Models, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified. Models ist das Projekt, das ContentModel, EditHistory und UserDetail enthält.Isolierte RazorEngine kann Modell nicht an andere AppDomain übergeben

public class ContentModel 
{ 
    public string Html { get; set; } 
    public string Title { get; set; } 
    public EditHistory History { get; set; } 
} 

public class EditHistory 
{ 
    public IReadOnlyCollection<UserDetail> Authors { get; set; } 
} 

public class UserDetail 
{ 
    public string Name { get; set; } 
    public string EmailAddress { get; set; } 
} 

Ich Einwickeln ContentModel in einem RazorDynamicObject als solche: Razor.Run("default.cshtml", typeof(ContentModel), RazorDynamicObject.Create(cm));

Wie oben erwähnt, funktioniert es ohne EditHistory vorhanden ist, aber nicht, wenn es ist.

Die Sandbox eingerichtet ist wörtlich laut, wie es bei https://antaris.github.io/RazorEngine/Isolation.html

getan Wie bekomme ich es mit komplexen benutzerdefinierten Typen zu arbeiten?

Unter ASP.NET ausgeführt.

Bearbeiten Ich habe eine minimale Reproduktion des Problems erstellt, das ich gegenüberstelle. Es ist bei https://github.com/knightmeister/RazorEngineIssue. Wenn die Paketwiederherstellung fehlschlägt, manuell install-package razorengine.

+2

was, wenn Sie 'öffentliche EditHistory Geschichte ersetzen geschieht {get; set;}' mit 'öffentlicher IReadOnlyCollection History {get; set;} 'und auch der gleiche Test mit einem einfachen Typ' public IReadOnlyCollection History {get; set;} '? Könnte die Nur-Lese-Sammlung das Problem sein? Was, wenn Sie eine "IList" oder "IEnumerable" verwendet haben? Gleiche Ergebnisse? – Tommy

+2

Gibt es eine Chance, ein einfaches VS-Projekt zu erstellen, das dieses Problem reproduziert und irgendwo veröffentlicht (z. B. GitHub)? –

+2

@CaioProiete - gute Idee. Ich habe das Gefühl, dass nicht viele Leute mit diesem speziellen Modul vertraut sein werden. Ich bin nicht, aber bin neugierig, genau herauszufinden, was den Fehler verursacht (verschachtelte komplexe Typen, die Nur-Lese-Sammlung, etc.) – Tommy

Antwort

4

Zunächst einmal; Ich konnte deinen GitHub-Code nie ausführen. Das Folgende basiert auf meinem eigenen Reproduktionscode.

Ich denke, dass Sie immer kann nicht -exceptions Datei oder Assembly geladen werden, da beim Setup der Sandbox AppDomain Sie Einstellung:

adSetup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase; 

Dies wird nicht in ASP.NET arbeiten weil Assemblys im Unterordner bin sind. Um das zu beheben, einfach das tun, statt:

adSetup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase 
          + "\\bin"; 

jedoch ASP.NET wird standardmäßig shadow copy assemblies. Wenn Sie nur diese Änderung vornehmen, wird wahrscheinlich eine weitere Ausnahme ausgelöst:

ArgumentException: Objekttyp kann nicht in Zieltyp konvertiert werden.

Das liegt daran, dass die Assemblys, die in der Standard-App-Domäne und in der Sandbox geladen sind, verwechselt werden. Die in der Standard-Anwendungsdomäne befinden sich in einem temporären Schattenkopie-Speicherort und die in der Sandbox befinden sich im bin-Ordner des Stammwurzels Ihrer Webanwendung.

Der einfachste Weg, dies zu beheben ist, indem Sie die folgende Zeile unter <system.web> in Web.config Schatten Kopieren deaktivieren:

<hostingEnvironment shadowCopyBinAssemblies="false"/> 

Darüber hinaus; Ich denke, es ist besser und einfacher zu überspringen mit RazorDynamicObject und markieren Sie stattdessen Ihre Modelle mit [Serializable]. In der Tat habe ich nie RazorDynamicObject richtig funktioniert.

Der Rest dieser Antwort fasst zusammen, was ich


Ich denke, dass dies aufgrund eines Fehlers oder Einschränkung in RazorEngine zu diesem Schluss zu kommen, tat. (Ich bin nicht so sicher über diese mehr, ist es sehr gut, dass Schatten Kopieren sein könnte und RazorDynamicObject kann zusammen nicht)

ich ein paar Stunden verbracht haben, um herauszufinden, wie diese Funktion zu erhalten, aber Ich habe immer eine Sicherheitsausnahme von RazorEngine erhalten. Es gibt jedoch eine mögliche Umgehung: Graben Sie RazorDynamicObject und markieren Sie Ihre Modellklassen als serialisierbar

[Serializable] 
public class ContentModel 
{ 
    public string Html { get; set; } 
    public string Title { get; set; } 
    public EditHistory History { get; set; } 
} 

[Serializable] 
public class EditHistory 
{ 
    public IReadOnlyCollection<UserDetail> Authors { get; set; } 
} 

[Serializable] 
public class UserDetail 
{ 
    public string Name { get; set; } 
    public string EmailAddress { get; set; } 
} 

Und tun:

Razor.Run("default.cshtml", typeof(ContentModel), cm); // no RazorDynamicObject 

Ich konnte nicht Ihren Repro Code zum Laufen bringen, so habe ich meine eigenen basierend auf Ihrem Code:

  1. a Erstellen Neue Konsolenanwendung (Visual Studio)

  2. Im Paket-Manager-Konsole ausführen: install-package razorengine

  3. Copy-Code von Ihrem Repro:

  4. Modelle mit [Serializable] kennzeichnen.

  5. entfernen RazorDynamicObject

  6. Um sicherzustellen, dass wir wirklich Benutzerdaten von der Autorenliste machen können, die Testvorlage ändern:

    string template = "@Model.History.Authors[0].EmailAddress"; 
    
  7. Auch um diese Vorlage funktioniert, ändern Authors in EditHistoryIReadOnlyCollection<>-IReadOnlyList<>

Ich habe einen GIST mit dem erhaltenen Code:
https://gist.github.com/mwikstrom/983c8f61eb10ff1e915a

Dies funktioniert für mich. Es druckt [email protected] wie es sollte.


ASP.NET wird Shadow Copy Assemblies standardmäßig und das wird zusätzliche Probleme mit Sandboxing verursachen.

Um diese Arbeiten unter ASP.NET erhalten Sie folgende Änderungen zu tun haben:

  1. deaktivieren ASP.NET Schatten Kopieren durch die folgenden unter <system.web> in der Datei Web.config hinzu:

    <hostingEnvironment shadowCopyBinAssemblies="false"/> 
    
  2. Append \bin an den Anwendungsbasispfad der Sandbox anhängen. So in createRazorSandbox(...) tun:

    adSetup.ApplicationBase = 
        AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "\\bin"; 
    

Ich habe dies getestet und es funktioniert gut. Mein Testprojekt ist einfach:

  • Eine leere ASP.NET Web Application (mit Visual Studio erstellt), mit install-package razorengine

  • <hostingEnvironment shadowCopyBinAssemblies="false"/> in Web.config.

  • Die folgende Global.asax.cs:

https://gist.github.com/mwikstrom/ea2b90fd0d306ba3498c


Es gibt andere Alternativen (außer deaktivieren Schatten Kopieren) hier aufgelistet:

https://github.com/Antaris/RazorEngine/issues/224

+0

Hallo, vielen Dank für den Versuch.Ich habe das vor dem Posten versucht, und ich habe es gerade mit dem Beispiel versucht, das ich bei GitHub veröffentlicht habe (siehe OP) - hast du es in Gang gesetzt? – Sam

+0

@Sam: Bitte sehen Sie meine letzte Änderung, die zeigt, was ich getan habe, um es zu starten. –

+0

schätzen Sie Ihre Hilfe, aber dies funktioniert nicht unter ASP.NET. Es muss unter ASP.NET ausgeführt werden. – Sam

1

ich meist don‘ t verwenden Komplexe Typen aber eine generelle Regel ist normalerweise, dass nur primitive Datentypen ok übertragen werden (meine eigene Regel, da Werte für mich sonst oft verloren gehen). Bei der Betrachtung eines alten Quellcodes habe ich jedoch bemerkt, dass ich viele komplexe Typen verwendet habe, aber ich habe sie in den Controller eingegeben (z. B. in Public ActionResult Index()). Nach einiger Lektüre denke ich es, wenn Sie etwas ähnliches wie diese verwenden könnte funktionieren (ungetestet, MSDN source, 2nd source):

[MetadataType(typeof(EditHistory))] 
public partial class ContentModel 
{ 
    public string Html { get; set; } 
    public string Title { get; set; } 
    public EditHistory History { get; set; } 
} 

[MetadataType(typeof(UserDetail))] 
public partial class EditHistory 
{ 
    public IReadOnlyCollection<UserDetail> Authors { get; set; } 
} 

public class UserDetail 
{ 
    public string Name { get; set; } 
    public string EmailAddress { get; set; } 
}