2015-06-28 27 views
24

Nella mia applicazione Asp.Net MVC, ho un file di visualizzazione (.cshtml) che ha riferimento a una libreria esterna che verrà caricato in fase di esecuzione. così dopo l'avvio dell'app, carico l'assembly tramite Assembly.Load e registro i controller con il mio custom ControllerFactory e tutto è ok.Come fare riferimento all'assemblaggio in mvc in fase di esecuzione

Ma, in alcuni punti di vista che ha riferimenti alla assemblea caricate dinamicamente, getta il:

compilatore messaggio di errore: CS0234: Il tipo o dello spazio dei nomi il nome 'MyDynamicNamespace' non esiste nello spazio dei nomi 'MyApp' (ti manca un riferimento all'assembly?)

eccezione che indica che il compilatore del rasoio non è in grado di risolvere il relativo assieme.

La mia domanda è che, c'è un modo per registrare l'assembly in fase di esecuzione, in modo che il compilatore del rasoio possa accedervi e risolverlo?

Avviso che non posso usare BuildManager.AddReferencedAssembly metodo perché il mio assemblaggio deve essere caricato dopo l'avvio applicazione, e il BuildManager non lo supporta.

+1

Non sono sicuro del motivo per cui è necessario caricare l'assieme dopo l'avvio dell'app? Quello non sarebbe un caso d'uso normale per le librerie esterne. – Claies

+2

è qualcosa di simile a un plugin o pensa a applicazioni web modulari come i frutteti cms. in realtà l'assemblea con le sue viste arriva in fase di esecuzione che l'utente dà! :) –

+1

Non credo che questo sia possibile in quanto quando si usa roslyn in un ambiente dnx il compilatore dinamico cerca di risolvere le dipendenze usando project.json come parte del processo di compilazione. L'assembly caricato dinamicamente non verrà elencato in project.json e quindi il compilatore fallirà. Immagino che in teoria sarebbe possibile regolare dinamicamente il project.json prima di riflettere la nuova dipendenza dopo l'avvio e prima che la vista venga caricata, ma onestamente non ho idea se funzionasse e sarebbe un trucco al meglio. Anche se funzionasse, potrebbe rompersi in futuro. –

risposta

9

1) Non è consigliabile che le viste utilizzino direttamente riferimenti esterni o riferimenti esterni caricati in modo dinamico. Astrarre questo facendo interagire la vista con un controller. Fai in modo che il controllore trasmetta un oggetto dati alla tua vista che è noto al momento della compilazione dall'applicazione (in altre parole, un oggetto noto alla tua applicazione Web in fase di compilazione). Questo è per isolare completamente (astratto) il business specifico del plugin dal tuo punto di vista. Quindi fai interagire il tuo controller con il "plugin".

2) Non so come funzioni la vostra "fabbrica personalizzata" ma oggigiorno non costruiamo più "fabbriche personalizzate". Al contrario, sfruttiamo i contenitori di iniezione di dipendenza come Microsoft Unity (o Ninject, o Castle Windsor o ecc.). Creare "fabbriche personalizzate" è molto vecchio stile e in pratica stai reinventando la ruota che è stata risolta con l'iniezione di dipendenza.

3) Per quanto riguarda il caricamento dinamico assembly esterni, non so se lo avete ragione, ma ecco un link:

Dynamically load a type from an external assembly

4) In genere, un design plug espone le interfacce che sono noti alla tua applicazione web principale al momento della compilazione. Ciò che nasconde il design del plugin è l'implementazione che può cambiare da un plugin all'altro. La cosa importante è che ogni plugin implementa le stesse interfacce pubbliche, quelle che sono previste dalla tua app web principale. Di solito, si avranno queste interfacce in un progetto "Comune" separato a cui fanno riferimento entrambi, la propria applicazione web principale e il proprio plugin che implementa tali interfacce. Pertanto, dalla tua app web principale, saprai quali sono le interfacce pubbliche dei tuoi plugin, puoi caricare dinamicamente l'assembly esterno e utilizzare la riflessione C# per trovare le classi che implementano tali interfacce e caricarle nel tuo contenitore di dipendenze. Allo stesso modo, chiunque desideri sviluppare un plug-in per la tua app Web dovrà implementare le interfacce definite nel progetto "Comune".

Nota: "Comune" è solo un nome casuale che ho dato al progetto. Puoi chiamarlo "PluginInterface" o qualsiasi altra cosa tu voglia.

Dopodiché, avere il controller che preleva tutto ciò di cui ha bisogno dal contenitore di iniezione delle dipendenze è banale.

Nota: le interfacce del plug-in avranno probabilmente entità di input e output. Queste entità sono condivise tra la tua app web principale e il tuo plug-in. In tal caso, poiché queste entità fanno parte delle interfacce, devono essere nel progetto "Comune". Potresti essere tentato dal fatto che il tuo controller ritorni tali entità direttamente alla tua vista, ma non avrai un'astrazione perfetta tra la tua vista e il tuo plugin. Non avere astrazioni perfette è per un'altra discussione.

Spero che aiuti!

+1

Il tuo 3 non ha senso in questa situazione, poiché questa domanda si basa sul presupposto che è necessario influenzare il processo di build dinamico di asp.net –

+2

La domanda dell'OP riguarda il "pattern di progettazione del plugin" e ho fornito informazioni suil modo giusto per farlo Non ha nulla a che fare con "il processo di compilazione dinamica di ASP.NET". Resto dalla mia risposta. L'OP sperava che potesse usare 'BuildManager' per implementare il suo pattern di progettazione di plugin, ma come ha scoperto non ha niente a che fare con quello. – TchiYuan

+2

@Tchi In un primo momento, grazie mille per la risposta. Ci sono cose buone, ma in realtà io spurgo che la vista di un'azione dovrebbe essere in grado di accedere a qualsiasi spazio dei nomi che l'azione ha, sembra essere una normale aspettativa. Hovever ho un DDD esaustivo per fornire interfacce comomn ma questo non è un buon motivo per emettere alcun riferimento all'interno di una vista ai suoi spazi dei nomi di plugin o servizi come ViewModels, DataProvider, enumerazioni, ... :) –

6

Come amministratore Sys, vorrei raccomandare un periodo di manutenzione, soprattutto se il file che sostituisci incasina qualcos'altro. Anche se il tuo periodo di manutenzione è solo mezz'ora, è una buona pratica.

Come per la DLL e la ricompilazione ... in genere il processo di lavoro IIS (il servizio che esegue il pool di applicazioni) verrà riciclato a intervalli normali in base alla configurazione di IIS e all'utilizzo della memoria. Quando ciò accade, l'applicazione ricompilerà se qualcosa richiede il JIT. Termina anche tutte le sessioni utente aperte in quanto si ferma fisicamente e quindi si riavvia. Il processo di lavoro monitora anche la directory root (come hai detto) per eventuali modifiche ai file. Se ne viene trovato uno, la ricompilazione viene forzata. Solo perché una dipendenza viene modificata non impone una ricompilazione. Se pre-compili la tua DLL, l'unica cosa che rimane da compilare è qualsiasi codice all'interno del tuo vero file ASPX e questo usa il JIT che compila ogni volta. Da quello che hai descritto che IIS non dovrebbe aver bisogno di ricompilare o riavviare, sembra un altro problema in cui IIS si blocca quando si sostituisce il file. Potrebbe essere necessario coinvolgere un amministratore di sistema per esaminare i registri di IIS.

Buona fortuna!

http://msdn.microsoft.com/en-us/library/ms366723.aspx

http://msdn.microsoft.com/en-us/library/bb398860.aspx

+0

Attualmente sto riavviando manualmente il 'IIS', ma non è esattamente quello che voglio. Spero un giorno di avere la soluzione o qualcuno di aiuto. Grazie @Farhad –

2

Ecco una nota che può aiuta: se non sta caricando gli assembly dalla directory /bin, è necessario assicurarsi che il percorso per le assemblee sia rilevabile:

AppDomain.CurrentDomain.AppendPrivatePath(path_to_your-dyna_assembly); 
+2

Grazie per l'attenzione Javad, ma sfortunatamente non mi aiuta, mai il problema non è quello. l'assembly è rilevabile anche se carica da un percorso che è stato contrassegnato come ''. e inoltre ho implementato un risolutore di assiemi che funziona bene per me. ma quando una pagina va compilata, il contesto del compilatore ('BuildManager') non accede o fa riferimento all'assembly. –