2016-03-30 10 views
9

Attualmente stiamo sviluppando un sistema dinamico che deve caricare alcune estensioni in fase di esecuzione.ASP MVC Core RC1 mette controller, viste e modello in altri assembly caricati in fase di esecuzione

Un'estensione è costruita sulla stessa architettura dell'app MVC, che significa una cartella controller, con classi che termina con Controller, View e ViewComponents associati che si trovano in/View/ControllerName e relativi modelli.

Non è possibile aggiungere questo progetto come riferimento al progetto, così ho creato un middleware che li carica in fase di esecuzione:

foreach (var item in extensions) 
{ 
    Assembly.LoadFrom([email protected]"extensions\{item.Name}.dll"); 
} 

Fin qui tutto bene, vengono caricati sul runtime. Ma quando provo ad accedere a un percorso creato in uno dei controller di estensione, WebSite mi dà una risposta 404.

Ho provato ad aggiungere l'estensione come riferimento e funziona bene, quindi questo non è un problema all'interno della mia estensione.

Come posso registrare il controller di mia DLL nel sito principale MVC?

Questo non è ASP MVC 4, questo è ASP core, quindi, sembra che questa risposta non è valida: asp.net mvc put controllers into a separate project

Sebbene Dependency Injection potrebbe essere una soluzione, non trovato alcuna soluzione per rendere la mia estensione registra i servizi per se stesso (ed è complicato per i creatori di estensioni).

lato controller

mio di routing per le estensioni è definito:

[Route("[controller]/[action]")] 
public class LotteryController : Controller { ... } 

Sul mio Startup.cs, ho mantenuto il percorso di default in realtà:

app.UseMvc(routes => 
     { 
      routes.MapRoute(
       name: "default", 
       template: "{controller=Home}/{action=Index}/{id?}"); 
     }); 

Il fatto è che io voglio la mia estensione abilitare il percorso: http://localhost/Lottery/Index

E mi dà una pagina vuota. Il mio attuale azione Index, a scopo di test, è

// GET Index 
public IActionResult Index() 
{ 
    return Content("From extension"); 
    //return View(); 
} 

Ed ecco la mia estensione progetto gerarchia

enter image description here

+0

È possibile che il problema riguardi il routing piuttosto che il codice responsabile del caricamento delle estensioni? Forse potresti fornire il codice del controller e/o la configurazione MVC in Startup.cs? – lawst

+0

Aggiunti alla mia domanda – cdie

+0

Ok, quindi sembra che tu stia utilizzando il routing predefinito. Potete anche fornire il metodo di controllo per "Indice"? Hai anche citato "View/ControllerName" nella tua domanda, tuttavia la struttura della directory di visualizzazione predefinita dovrebbe essere "Views/ControllerName", quindi puoi anche confermare che la vista si trovi nella posizione corretta? – lawst

risposta

7

MVC troverà automaticamente i controller che ereditano da Controller all'avvio e li comprendono. Ciò funzionerà per gli assembly esterni, ma più probabilmente funzionerà solo per quelli collegati staticamente.

Se si caricano dinamicamente, è possibile provare a ritardare l'avvio di MVC o registrare separatamente gli assiemi.

Questo frammento di codice mostra come cercare altri assiemi per i controller. L'articolo completo che spiega questo può essere trovato here. Potresti riuscire a usarlo dopo aver caricato i tuoi assiemi per forzare MVC a cercarli per i controller.

services.AddMvc().AddControllersAsServices(new[] 
{ 
    typeof(MyController).Assembly, 
    typeof(ExternalPocoController).Assembly 
}); 

Questo cercherà quegli assembly per i controller. L'unica avvertenza è che è possibile che non riesca a trovare le viste associate.Onestamente non ne sono sicuro, come ho sempre fatto con i controller WebAPI. Edit:This sembra che potrebbe essere un modo per ottenere il punto di vista di lavoro

Come nota a margine, probabilmente sarei suggerisco sia utilizzando decoratori o più rotte di mappatura via alla vecchia maniera. Usare entrambi sembra una ricetta per i guai.

+0

Rispondendo alla nota a margine - a volte si desidera utilizzare l'instradamento di attributi ma si dispone di alcuni percorsi che si desidera caricare dopo che tutti gli altri sono stati caricati. Ho 4 percorsi (di centinaia) che carico dopo che tutto il routing degli attributi è stato curato, semplicemente perché il loro routing tramite Area Registration mi dà molto più controllo di Attribute Routing. Vedi http://stackoverflow.com/questions/33155259/is-it-possibile-per-cambiare-del-fornito-in-routing-table-when-using-attribute-r –

1

Quando si carica l'assieme, è necessario aggiungere istanze ActionDescriptor per le azioni manualmente. In realtà MVC6 utilizza 'Composite root' e crea una tabella di instradamento immutabile. È possibile implementare la vostra abitudine IActionDescriptorCollectionProvider e sostituire il predefinito in DI:

services.Replace(ServiceDescriptor.Describe(typeof(IActionDescriptorCollectionProvider), typeof(CustomActionDescriptorCollectionProvider), ServiceLifetime.Singleton)); 

e in getter di proprietà:

public ActionDescriptorCollection ActionDescriptors 

di default di ritorno (build in fase di avvio) e il proprio ActionDescriptor di. Nella mia soluzione creo un negozio intermedio dove inserisco il mio ActionDescriptor quando carico l'assembly dinamico e in IActionDescriptorCollectionProvider mi limito a controllare questo negozio