Versione brevedinamica Risoluzione dell'Assemblea/Gestione
Ho un'applicazione che utilizza un plug-in infrastrutture. I plug-in hanno proprietà configurabili che li aiutano a sapere come fare il loro lavoro. I plug-in sono raggruppati in profili per definire come completare un'attività ei profili sono archiviati in file XML serializzati da DataContractSerializer. Il problema è quando si leggono i file di configurazione, la deserializzazione dell'applicazione deve avere conoscenza di tutti i plug-in definiti nel file di configurazione. Sto cercando un modo per gestire la risoluzione dei plug-in sconosciuti. Vedere la sezione della soluzione proposta di seguito per un paio di idee che ho cercato di implementare, ma sono aperto a qualsiasi cosa (anche se preferirei non dover reinventare l'applicazione).
Particolare
Sfondo
ho sviluppato una sorta di Business Automation Sistema Processo per uso interno per l'azienda che sto attualmente lavorando per in C# 4. Rende uso completo dei 'plug-in' per definire tutto (dalle attività che devono essere eseguite alla definizione di unità di lavoro) e fa molto affidamento su un modello di configurazione dinamico che a sua volta si affida a C# 4/Oggetti dinamici DLR per soddisfare i lavori. È un po 'pesante durante l'esecuzione a causa della sua natura dinamica, ma funziona in modo coerente e funziona abbastanza bene per le nostre esigenze.
Include un'interfaccia utente di configurazione WinForms che utilizza ampiamente Reflection per determinare le proprietà/campi configurabili dei plug-in, nonché le proprietà/campi che definiscono ciascuna unità di lavoro da elaborare. L'interfaccia utente è anche costruita sulla parte superiore del motore BPA, quindi ha una conoscenza approfondita del modello oggetto (libero) messo in atto che consente al motore di svolgere il proprio lavoro, il che, per coincidenza, ha portato a diversi miglioramenti dell'esperienza utente, come , esecuzione del lavoro ad hoc e convalida in fase di configurazione dell'input dell'utente. Ancora una volta c'è spazio per miglioramenti, tuttavia, sembra fare il suo lavoro.
L'interfaccia utente di configurazione utilizza DataContractSerializer per serializzare/deserializzare le impostazioni specificate, pertanto qualsiasi plug-in referenziato dalla configurazione deve essere caricato prima (o al momento della) carico di configurazione.
Struttura
Il motore BPA è implementato come un assembly condiviso (DLL), che fa riferimento il servizio di BPA (un servizio di Windows), la configurazione dell'interfaccia utente (WinForms app), e un plug-in del tester (Versione dell'applicazione console del servizio Windows). Ciascuna delle tre applicazioni che fanno riferimento all'assembly condiviso include solo la quantità minima di codice necessaria per eseguire il proprio scopo specifico. Inoltre, tutti i plug-in devono fare riferimento a un assemblaggio molto sottile che fondamentalmente definisce solo l'interfaccia (o le interfacce) che il plugin deve implementare.
Problema
A causa del modello di estensibilità utilizzato nell'applicazione, c'è sempre stato un requisito che l'interfaccia utente di configurazione viene eseguito dalla stessa directory (sullo stesso PC), come l'applicazione di servizio. In questo modo l'interfaccia utente è sempre a conoscenza di tutti gli assembly di cui il servizio è a conoscenza, in modo da poter essere deserializzati senza incorrere in gruppi mancanti.Ora che ci stiamo avvicinando al roll out del sistema, una richiesta di consentire l'IU di configurazione da remoto su qualsiasi PC nella nostra rete proviene dai nostri amministratori di rete per motivi di sicurezza. Generalmente questo non sarebbe un problema se esistesse sempre un gruppo noto di assembly da distribuire, tuttavia, con la possibilità di estendere l'applicazione utilizzando gli assembly creati dall'utente, ci deve essere un modo per risolvere gli assembly da cui i plug-in può essere istanziato/usato.
proposto (potenzialmente ovvio) Soluzione
Aggiungere un servizio WCF per l'applicazione di servizio per consentire le operazioni CRUD tipici contro le configurazioni che l'istanza di servizio è a conoscenza e rielaborare il UI configurazione ad agire più come SSMS con un modello Connect/Disconnect. Questo in realtà non risolve il problema, quindi dovremmo anche esporre una sorta di ServiceContract dall'applicazione di servizio per consentire l'interrogazione degli assembly a cui sa/ha accesso. Va bene e abbastanza semplice, tuttavia la domanda sorge spontanea, "Quando l'UI dovrebbe informarsi sugli assembly di cui il Servizio è a conoscenza?" In fase di connessione, è possibile inviare tutti gli assembly dal servizio all'interfaccia utente per assicurarsi che sia sempre a conoscenza di tutti gli assembly che il servizio esegue, ma ciò si confonde con i conflitti di gestione di AppDomain (potenzialmente inutilmente) e di assembly. Quindi ho suggerito di collegarmi agli eventi AppDomain.AssemblyResolve/AppDomain.TypeResolve per scaricare solo gli assembly di cui il client non è ancora a conoscenza e solo se necessario. Ciò non risolve necessariamente i problemi di gestione di AppDomain, ma aiuta sicuramente ad affrontare i conflitti di versione e i problemi correlati.
Domanda
Se hai bloccato con me così a lungo mi congratulo e vi ringrazio, ma ora sto finalmente arrivare alla domanda reale qui. Dopo mesi di ricerche e infine giungere a una conclusione, mi chiedo se qualcuno qui ha dovuto affrontare un problema simile e come hai affrontato le insidie e le carenze? Esiste un modo standard di gestire ciò che mi è sfuggito completamente o hai qualche consiglio basato su come hai visto questo gestito con successo in passato? Vedi qualche problema con gli approcci proposti o puoi offrire un'alternativa?
Sono consapevole che non tutti vivono nella mia testa quindi per favore fatemi sapere se avete bisogno di ulteriori chiarimenti/spiegazioni. Grazie!
Aggiornamento
ho dato MEF una scossa giusta e sentire che è troppo semplicistico per i miei scopi. Non è che non potrebbe essere piegato a gestire i requisiti di plug-in della mia applicazione, il problema è che sarebbe troppo ingombrante e sporco per renderlo fattibile. È un bel suggerimento e ha un grande potenziale, ma nel suo stato attuale non è ancora arrivato.
Qualche altra idea o feedback sulle mie soluzioni proposte?
Aggiornamento
Non so se il problema che sto incontrando è semplicemente troppo localizzata, se non sono riuscito a descrivere correttamente quello che sto cercando di realizzare, o se questa domanda è semplicemente troppo irragionevolmente lungo da leggere nella sua interezza; ma le poche risposte che ho ricevuto sono state abbastanza utili da aiutarmi a riflettere diversamente sul problema e identificare alcune carenze in quello che sto cercando.
In breve, quello che sto cercando di fare è prendere tre applicazioni che nel loro stato corrente condividono le informazioni (configurazione/assiemi) usando una struttura di directory comune e cercano di far funzionare quelle applicazioni su una rete con un impatto minimo su usabilità e architettura.
parti di file sembrano come la risposta ovvia a questo problema (come @SimonMourier proposto nei commenti), ma il loro utilizzo si traduce in mancanza di controllo e debugability quando qualcosa va storto. Posso vederli come una valida soluzione a breve termine, ma a lungo termine non sembrano fattibili.
+1 Per una domanda ben descritta! –
Scusa se sembra stupido, ma non puoi semplicemente distribuire i tuoi plugin in modo centralizzato su una condivisione e (a condizione che i diritti e CAS siano a posto) caricarli da questa condivisione, da qualsiasi processo (Servizio, Config, ecc.)? Altra domanda mentre ci sono, sei a conoscenza del fantastico ma poco conosciuto set di spazi dei nomi System.AddIn: http://msdn.microsoft.com/en-us/library/gg145020.aspx? –
@SimonMourier - Grazie per i suggerimenti. Sì, ho sentito parlare di MAF ma è più pesante di quanto stavo cercando quando ho scritto il mio. Per quanto riguarda la distribuzione dei plug-in su una condivisione di file, l'ho considerato per circa 5 secondi e probabilmente potrebbe funzionare ma sembra solo sporco. Penso che preferirei una soluzione più integrata (in poche parole: sono un programmatore, quindi mi piacerebbe dover codificare qualcosa). –