2015-04-21 49 views
9

Tratto da: http://docs.autofac.org/en/latest/integration/signalr.html:OWIN + SignalR + Autofac

"Un errore comune in materia di integrazione OWIN è l'uso del GlobalHost In OWIN si crea la configurazione da zero Non si dovrebbe fare riferimento GlobalHost ovunque quando si utilizza l'integrazione OWIN.. ".

Sembra ragionevole. Tuttavia, come si dovrebbe risolvere IHubContext da un ApiController, come il solito (non OWIN):

GlobalHost.ConnectionManager.GetHubContext<MyHub>()?

non riesco a trovare un punto di riferimento su questo da nessuna parte, e l'unico metodo che ho per ora è quello di registrare l'istanza HubConfiguration all'interno dello stesso contenitore e fare questo:

public MyApiController : ApiController { 
    public HubConfiguration HubConfig { get; set; } // Dependency injected by 
                // PropertiesAutowired() 

    public IHubContext MyHubContext { 
    get { 
     return HubConfig 
     .Resolver 
     .Resolve<IConnectionManager>() 
     .GetHubContext<MyHub>(); 
    } 
    } 

    // ... 

} 

Tuttavia, questo sembra abbastanza verboso per me. Qual è il modo corretto per farlo? Per essere più specifici, c'è un modo pulito per registrare IConnectionManager?

EDIT:

Quello che ho finito per fare è qualcosa di simile:

var container = builder.Build(); 
hubConfig.Resolver = new AutofacDependencyResolver(container); 

app.MapSignalR("/signalr", hubConfig); 

var builder2 = new ContainerBuilder(); 
builder2 
    .Register(ctx => hubConfig.Resolver.Resolve<IConnectionManager>()) 
    .As<IConnectionManager>(); 

builder2.Update(container); 

ma ho la sensazione che ci deve essere un modo più semplice per ottenere che IConnectionManager iniettato nel controller.

+1

Sembra che nel mix sia presente anche l'API Web. È questo il caso? –

+0

Posso chiederti perché non stai facendo un'iniezione di costruttore? Qui hai un'enorme dipendenza dal tuo contenitore. – Anders

+0

@TravisIllig: Sì, scusa se non ero esplicito su quello. Quando ho detto ApiController intendevo il controller WebAPI. – itim

risposta

9

Questa risposta è un po 'tardiva, ma qui va.

  • Raccomando hub fortemente tipizzati.
  • È necessario aggiungere specifiche registrazioni per gli hub fortemente tipizzati.
  • io non utilizzare il GlobalHost
    • Invece io uso la configurazione creata per OWIN registrazione.

Dichiarazione Hub

public interface IMyHub 
{ 
    // Any methods here for strongly-typed hubs 
} 

[HubName("myHub")] 
public class MyHub : Hub<IMyHub> 

Hub Registrazione

Dalla tua registrazione Autofac

// SignalR Configuration 
var signalRConfig = new HubConfiguration(); 

var builder = // Create your normal AutoFac container here 

builder.RegisterType<MyHub>().ExternallyOwned(); // SignalR hub registration 

// Register the Hub for DI (THIS IS THE MAGIC LINE) 
builder.Register(i => signalRConfig.Resolver.Resolve<IConnectionManager>().GetHubContext<MyHub, IMyHub>()).ExternallyOwned(); 

// Build the container 
var container = builder.Build(); 

// SignalR Dependency Resolver 
signalRConfig.Resolver = new Autofac.Integration.SignalR.AutofacDependencyResolver(container); 

app.UseAutofacMiddleware(container); 
app.MapSignalR("/signalr", signalRConfig); 

Risolvere l'hub nel codice sfondo

Utilizzando il metodo di estensione AutoFacs AutowiredProperties(), può risolvere il contesto corretto (può anche essere nel costruttore, se lo si desidera).

public IHubContext<IMyHub> InstanceHubContext { get; [UsedImplicitly] set; } 
+0

Grazie. Brillante. Utilizzo una soluzione leggermente modificata: 'builder.RegisterType (). As (). SingleInstance();' 'builder.Register (context => context.Resolve (). Risolvi (). GetHubContext ()). ExternallyOwned(); 'e usa autofac per risolvere resolver:' hubConfiguration.Resolver = container.Resolve (); 'Lo stesso per' httpConfiguration' per uniformità. –

+0

Questa è la risposta corretta. Grazie! – itim

6

È possibile spostare parte di questo codice ripetuto (presumo che lo IHubContext sia utilizzato anche in alcune altre classi e venga recuperato nello stesso modo) nella registrazione del contenitore.

La prima cosa è registrare le istanze IHubContext, presumo che tu abbia più hub nel progetto. In tal caso, i servizi devono essere registrati come named services.

builder 
    .Register<IHubContext>(c => c.Resolve<IConnectionManager>().GetHubContext<MyHub>()) 
    .Named<IHubContext>("MyHub"); 

classi, che desiderano utilizzare IHubContext possono ora ricevere come parametro del costruttore o come proprietà. Ma dobbiamo dire al contenitore quale istanza dovrebbe iniettare. Questo può essere fatto in configurazione contenitore, in molteplici modi

costruttore può utilizzare ResolvedParameter per selezionare correttamente IHubContext implementazione

// example class 
public class SampleClass { 
    public SampleClass(IHubContext context) { } 
} 

// and registration for this class 
builder.RegisterType<SampleClass>() 
    .WithParameter(new ResolvedParameter((pi, ctx) => 
    { 
     // only apply this to parameters of IHubContext type 
     return pi.ParameterType == typeof(IHubContext); 
    }, (pi, ctx) => 
    { 
     // resolve context 
     return ctx.ResolveNamed<IHubContext>("MyHub"); 
    })); 

iniezione proprietà, è anche un po 'complicato.E 'necessario per risolvere corretto esempio nel OnActivated richiamata, per esempio come questo:

// example class 
public class SampleClass2 
{ 
    public IHubContext Context { get; set; } 
} 

// registration for this case 
builder.RegisterType<SampleClass2>() 
    .PropertiesAutowired() 
    .OnActivated(e => e.Instance.Context = e.Context.ResolveNamed<IHubContext>("MyHub")); 
+0

Sembra più pulito, ma ancora un po 'troppo prolisso e ho la sensazione che potrebbe esserci un modo più semplice. Il mio esempio è un po 'semplificato, ma quello che vorrei davvero è l'istanza di IConnectionManager iniettata nei controller, se possibile (al momento non posso farlo senza aggiornare il contenitore di Autofac dopo la sua costruzione, come: 'var connManager = hubConfig.Resolver.Resolve (); builder.Register (ctx => connManager); builder.Update (container) '. Provare:' builder.Register (ctx => ctx.Resolve ()) 'non funziona per me. – itim

+0

Ah , Ho erroneamente ipotizzato che tutti gli interni SignalR siano registrati nel container Autofac, infatti, 'AutofacDependencyResolver' delega la costruzione di componenti SignalR interne a' DefaultDependencyResolver' che proviene da SignalR stesso.Quindi il tuo approccio sembra valido ed è in linea con gli esempi di Microsoft (questo è per Ninject ma sembra simile a quello che state facendo http://www.asp.net/signalr/overview/advanced/dependency-injection). Un'altra opzione sarebbe quella di registrare anche i servizi SignalR interni in co ntainer, ma questo potrebbe portare problemi di manutenzione durante gli aggiornamenti SignalR. – drax

2

ho fatto simile a te stesso, che ha ottenuto si lavora in Owin per me

builder.RegisterInstance(config.Resolver).As<IDependencyResolver>(); 
builder.Update(container); 

quindi utilizzare questo per ottenere la mia hub

Resolve<IDependencyResolver>().Resolve<IConnectionManager>().GetHubContext<MyHub>(); 

Spero che questo aiuti altri là fuori

1

Easi La soluzione che ho trovato è in qualche modo un mix tra le risposte qui, ma per me sembra il modo migliore per gestire questo e mantenere le migliori pratiche per SignalR e SignalR IntegrationR:

Nelle classi che voglio un contesto hub I avere una proprietà

public IConnectionManager ConnectionManager { get; set; } 

che mi iscrivo come segue:

newBuilder.RegisterInstance(resolver.Resolve<IConnectionManager>()); 

dove resolver è un new AutofacDependencyResolver(container);

Poi, ho praticamente usare il ConnectionManager molto simile a GlobalHost:

var context = ConnectionManager.GetHubContext<WorkshopsHub>(); 

Poi chiamo context.Clients.All.clientMethod();

In questo modo sono facilmente in grado di aggiornare i client dall'esterno del mozzo, hanno il codice facilmente mantenibile e seguire il migliore pratiche (penso e spero: D).

Ho anche pensato di registrarli e risolverli all'avvio, ma sembra un compito molto difficile da fare, con pochissimi benefici (oltre a sentirsi bene quando ci riesce).

Spero che questo aiuti! Buona fortuna!

Problemi correlati