2011-06-24 15 views
13

Projektuję strukturę wtyczki dla ASP.NET MVC3, używając widoków maszynki Razor, i mam problem z poprawnym działaniem osadzonych widoków.Struktura wtyczki z ASP.NET MVC3 i osadzonymi widokami Razor

Ramy Wtyczka przeznaczona jest mieć te funkcje:

  • Każda wtyczka ma swoje własne modele, kontrolery i widoki. Widoki są wbudowane zasoby i kontrolery wywodzą się z klasy PluginController
  • wtyczek mają referencje zależność do wspólnej klasy biblioteki, który definiuje klasy bazowej PluginController
  • „shell” aplikacji WWW, który obsługuje wtyczki nie może zawierać odwołań do jakichkolwiek wtyczek w czasie projektowania, ponieważ nie wie w czasie projektowania, które wtyczki ma.
  • dll pluginu są opuszczane w folderze w aplikacji powłoki, która jest nie folder/bin
  • Skorupa dba:
    1. odkrywaniu wtyczek (przy użyciu odbicia)
    2. Rejestrowy wszystkie kontrolery (używam do tego Spring.Net)
    3. Tworzenie trasy do kontrolerów
    4. obsługujących pliki ostrzami (cshtml) poprzez zwyczaju VirtualPathProvider

Teraz wszystko działa poprawnie, z wyjątkiem sytuacji, gdy osadzone widoki zawierają odniesienia do typów w bibliotece DLL wtyczki. Potem się niesławny błąd (nazwy pominięta):

The type or namespace name '[Plugins]' does not exist in the namespace '[MyPluginSolution]' (are you missing an assembly reference?)

Powodem tego jest to, że kompilator csc która wywoływana jest czas pracy do kompilacji poglądy brzytwa tylko dostać odniesienia dll z folderu bin i GAC.

Próbowałem również wstępnego kompilowania widoków przy użyciu this technique, ale w końcu daje takie same wyniki, ponieważ środowisko wykonawcze nalega na kompilowanie opakowania dla wstępnie skompilowanego widoku maszynki.

Mógłbym oczywiście upuść DLL wtyczek w katalogu/bin, ale moje pytanie brzmi:

Czy istnieje sposób, aby zarejestrować bibliotek DLL w non-bin (i non-GAC) folder i leczyć jako "pierwszorzędni obywatele", aby mogli korzystać z widoków brzytwy?

Odpowiedz

14

Ok, roztwór znaleźć za pomocą this article.

Najpierw tworzę klasę z PreApplicationStartMethod. Ta metoda skanuje folder wtyczki i kopiuje pliki dll do AppDomain.DynamicDirectory.

Następnie każdy z tych dll są ładowane za pomocą BuildManager.AddReferencedAssembly.

I voila, mocno na maszynie Razor widoki pięknie się kompilują. Zobacz kod tutaj:

[assembly: PreApplicationStartMethod(typeof(MySolution.PluginHandler.PluginActivator), "Initialize")] 
namespace MySolution.PluginHandler 
{ 
    public class PluginActivator 
    { 
     private static readonly DirectoryInfo PluginFolderInfo; 

     static PluginActivator() { 
      PluginFolderInfo = new DirectoryInfo(HostingEnvironment.MapPath("~/plugins")); 
     } 

     public static void Initialize() { 
      CopyPluginDlls(PluginFolderInfo, AppDomain.CurrentDomain.DynamicDirectory); 
      LoadPluginAssemblies(AppDomain.CurrentDomain.DynamicDirectory); 
     } 

     private static void CopyPluginDlls(DirectoryInfo sourceFolder, string destinationFolder) 
     { 
      foreach (var plug in sourceFolder.GetFiles("*.dll", SearchOption.AllDirectories)) { 
       if (!File.Exists(Path.Combine(destinationFolder, plug.Name))) { 
        File.Copy(plug.FullName, Path.Combine(destinationFolder, plug.Name), false); 
       } 
      } 
     } 

     private static void LoadPluginAssemblies(string dynamicDirectory) 
     { 
      foreach (var plug in Directory.GetFiles(dynamicDirectory, "*.dll", SearchOption.AllDirectories)) { 
       Assembly assembly = Assembly.Load(AssemblyName.GetAssemblyName(plug)); 
       BuildManager.AddReferencedAssembly(assembly); 
      } 
     } 
    } 
} 

mam nadzieję, że może to pomóc w innych programistów, którzy chcą tworzyć czyste ramy plugin przy użyciu tych nowych technologii.

+0

Czy powodem, dla którego nie umieszczasz wtyczek w katalogu bin, jest to, że nie chcesz ponownie uruchomić aplikacji? to rozwiązanie ładuje tylko wtyczkę przy uruchamianiu aplikacji (BuildManager.AddReferencedAssembly) - czy dynamicznie można odwołać się do zespołu w katalogu dynamicDirectory? –

+0

Powodem jest to, że to rozwiązanie może mieć potencjalnie dużą liczbę wtyczek, każda z 3-5 bibliotekami DLL. A ponieważ nie można ich umieścić w podfolderach w katalogu/bin, preferowanym rozwiązaniem byłoby użycie do tego innego folderu. – lasseschou

1

Ostatnio David Ebbo pisał o wstępnej kompilacji widoków Razor na zgromadzenia. Możesz zobaczyć post here.

Powinieneś być w stanie uniknąć rejestrowania złożeń bezpośrednio przez dynamiczne ładowanie złożeń (zwykle używałbym do tego mojego kontenera IoC), a następnie wywoływania BuildManager.AddReferencedAssembly dla każdego zespołu wtyczek.

+0

Dzięki Ben. Ale w jego przypadku, podobnie jak w przypadku Chrisa van de Steeg, aplikacja hosta ma bezpośrednie odniesienie do zestawu wtyczek, więc nie rozwiązuje on niestety mojego problemu. – lasseschou

+0

Zaktualizowałem moją odpowiedź, ale zauważ, że to wszystko "w teorii" :) - więcej szczegółów http://haacked.com/archive/2010/05/16/three-hidden-extensibility-gems-in-asp-net -4.aspx –

+0

Witaj Ben, twoja ostatnia edycja wskazała mi właściwy kierunek. Rozwiązaniem była metoda pre-Application_Start, która kopiuje wszystkie biblioteki DLL wtyczki do AppDomain.DynamicDirectory, a następnie wywołuje BuildManager.AddReferencedAssembly(). W tym artykule pokazano, jak to zrobić, zarówno w pełnym zaufaniu, jak i średnim zaufaniu: http://shazwazza.com/post/Developing-a-plugin-framework-in-ASPNET-with-medium-trust.aspx. Sam opublikuję odpowiedź. – lasseschou

1

Proszę spojrzeć na kod źródłowy NOPCommerce. Ma ładną strukturę wtyczki opartą na pracy pod numerem Shannon.

1

Możesz także wybrać opcję "Powierzchnia" w MVC3 i 4, możesz stworzyć ładny system wtyczek. Daje rozdzielenie obsługi modelu wtyczki, widoku i kontrolera we własnym zespole.