asp.net külön appdomain minden pluginhoz

Fórumok

Hello!

Egy olyan feladatot kellene végrehajtanom, hogy ASP.NET alatt be kellene töltenem különböző plugineket. Ez eddig még meg is van, de nekem ezeket a plugineket menet közben el is kell tudnom engedni, mivel frissíteni is kell őket. Na itt jön a feketeleves. Ugyebár, ha a fő appdomainba töltöm be, akkor nem tudom elengedni, csak ha újraindul az alkalmazás, ha a fájlt felülírom, akkor újraindul a webapp (webdevben biztosan).
Utánaolvastam a dolgoknak, és jó lenne külön appdomaint készíteni és abba betölteni (mindegyiket egy újba, mert ha belehívtam a dll-be, nem megengedhető, hogy leálljon az egész alkalmazás, vagy maga a dllben futó kód!) Viszont már az elsőt sem tudom betölteni. Ezzel próbálkozok:


AppDomainSetup domaininfo = new AppDomainSetup();
domaininfo.ApplicationBase = Server.MapPath("~") + "bin\\MeasurementDLLs";
AppDomain newDomain = AppDomain.CreateDomain(dll,null, domaininfo);
//newDomain.TypeResolve += ((s, a) =>
//    {
//        return System.Reflection.Assembly.LoadFrom(a.Name);
//    });
newDomain.Load(File.ReadAllBytes(dll));
//System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFrom(dll);

Ha megpróbálom betölteni, akkor File Not Found exception-t dob. Ha az eseményre feliratkozok, akkor a feliratkozáskor dob egy kivételt, pedig odáig már nem jutok el, hogy meg is próbáljam, hogy betöltsem a dll-t.
Jelenleg úgy épül fel a programom, hogy

  • van egy dll, amiben benne van a webalkalmazásom. (betölti az IIS)
  • van egy dll, amit a plugin íroi felé bocsájtok ki, hogy megfelelő interfészeket használják, melyek alapján a megfelelő osztályokat hasznlájam a plugin dllekből. Ez referálva van a webalkalmazásos dllben, ezért az IIS betölti a default appdomainbe.
  • illetve van a harmadik, maga a plugin, amit szeretnék betölteni, de nem sikerül.

Ebben kérnék segítséget, hogy mit csinálok rosszul? Esetleg mit nem vettem észre.
Kerestem Google-n de pont ilyesmit nem találtam, a példakódok meg vagy nem fordultak le vagy ugyanúgy nem működött mint a sajátom.

Hozzászólások

Írj pontos exceptiont... És nem szép dolog bájtokból betölteni az assemblyt. Hivatkozz rá fájlnévvel. Nézegess fusion logot (fuslogvw.exe az SDK-ban).

--

Exception, ha nem vagyok az eseményre feliratkozva:
A(z) „ExamplePlugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null” fájl vagy szerelvény, illetve annak egyik függősége nem tölthető be. A rendszer nem találja a megadott fájlt.

Exception amikor feliratkozok az eseményre:
A(z) „WEBAPP, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null” fájl vagy szerelvény, illetve annak egyik függősége nem tölthető be. A rendszer nem találja a megadott fájlt.

Fontos, hogy a pluginekben nincs meghivatkozva a WEBAPP dll

Az appdomainnak hirtelenjében nem találtam meg azt a metódusát, hogy fájlnév alapján töltsön be. A DLL-eket egyelőre nem teszem a GAC-ba, és nem is nagyon szeretném.

- ha a \bin alá rakod a .dll-eket, mindig újra fog indulni az AppDomained ha változik (akkor is, ha sub-folderben vannak a cuccok)
- a FileNotFound exception alapján arra gondolnék, hogy itt még nincs semmi nagy mágia, egyszerűen rossz path-ről próbálod betölteni a .dll-t

Jelenleg úgy van megoldva, hogy a WEBAPP a bin könyvtárba fordul, úgy ahogy a fejlesztőknek szóló PluginDev is. a bin\measurementDlls mappába fordul az egy szem kísérleti pluginom.
Amikor a pluginokat be akarom tölteni akkor légyegében végig szaladok a measurementDlls mappán így:


foreach (string dll in Directory.EnumerateFiles(Server.MapPath("~") + "bin\\MeasurementDLLs", "*.dll", SearchOption.TopDirectoryOnly))

így a dll változóban a teljes elérési útvonal benne lesz. Eddig úgy töltöttem be a dll-eket, és vettem ki belőlük a szükséges osztályokat, hogy


System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFrom(dll);
foreach (Type type in assembly.GetTypes())
{
//ellenőrzés, type eltárolása
}

Ez szépen is működik csak nem lehet unloadolni az így betöltött DLL-t

De akkor átteszem, hogy a bin könyvtárral legyen egy szinten a plugin mappa

Szerk: áttettem máshová, átírtam az új appdomain path-jait


domaininfo.ApplicationBase = Server.MapPath("~") + "MeasurementDLLs";
domaininfo.PrivateBinPath = Server.MapPath("~") + "MeasurementDLLs";

de a helyzet változatlan.

Szerk2: Mivel a plugin megreferálja a PluginDev dll-t ezért fordításkor a plugin mellé másolódik az is. De próbáltam azt is, hogy betöltöm a plugindevet előtte, de az sem volt neki elég. Továbbra is hiányolja a plugin dll-jét vagy annak valamilyen függőségét betöltéskor, akár byte[]-ként adom át, akár a nevével hivatkozok rá.

Illetve, ha megpróbálok feliratkozi az TypeResolve eseményre akkor a következő Exceptiont kapom:


[System.Runtime.Serialization.SerializationException]
{"Hiba történt a célmetódushoz való kötéskor, mert az aláírás vagy a biztonsági átlátszóság nem felel meg a delegált típusnak."}

Ennyire már nem ismerem a CLR-t, nem tudom, hogy most mit hiányolhat.

Nekem így működik:

Három project:
- Website (referenciálja IMyInterface-t tartalmazó projectet)
- IMyInterface-t tartalmazó project
- Plugin1-et tartalmazó project, Plugin1 MarshalByRefObject-ből származik (referenciálja IMyInterface-t tartalmazó projectet)

var domain = AppDomain.CreateDomain("MyDomain");
var instance = (IMyInterface) domain.CreateInstanceFromAndUnwrap(@"C:\pathtodll\TestClass.dll", "MyPlugins.Plugin1");

Irodalom:
http://www.brad-smith.info/blog/archives/500

Az appdomainek közötti kommunikáció nagyon ineffektív, annyira, hogy érdemes megbarátkozni az apppool recyclevel.

nem ide, csak a belépés gomb ide irányított :(