Taken from: http://docs.autofac.org/en/latest/integration/signalr.html:
"A common error in OWIN integration is use of the GlobalHost. In OWIN you create the configuration from scratch. You should not reference GlobalHost anywhere when using the OWIN integration."
That sounds reasonable. However, how should one resolve IHubContext
from an ApiController, like the usual (non-OWIN):
GlobalHost.ConnectionManager.GetHubContext<MyHub>()
?
I can't find a reference on this one anywhere, and the only method I have by now is to register the HubConfiguration
instance within the same container and do this:
public MyApiController : ApiController {
public HubConfiguration HubConfig { get; set; } // Dependency injected by
// PropertiesAutowired()
public IHubContext MyHubContext {
get {
return HubConfig
.Resolver
.Resolve<IConnectionManager>()
.GetHubContext<MyHub>();
}
}
// ...
}
However, this seems quite verbose to me. What is the proper way to do it? To be more specific, is there a clean way to register IConnectionManager
?
EDIT:
What I ended up doing is something like:
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);
but I have a feeling there must be an easier way to get that IConnectionManager
injected in the controller.
This answer is a little belated but here goes.
public interface IMyHub
{
// Any methods here for strongly-typed hubs
}
[HubName("myHub")]
public class MyHub : Hub<IMyHub>
From your Autofac registration
// 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);
Using AutoFacs AutowiredProperties() extension method then it can resolve the correct context (can also be in the constructor if you like).
public IHubContext<IMyHub> InstanceHubContext { get; [UsedImplicitly] set; }
What you can do is to move some of this repeating code (I assume IHubContext
is also used in some other classes and it is fetched in the same way) into container registration.
First thing is to register IHubContext
instances, I assume you have multiple hubs in project. I that case, services have to be registered as named services.
builder
.Register<IHubContext>(c => c.Resolve<IConnectionManager>().GetHubContext<MyHub>())
.Named<IHubContext>("MyHub");
Classes, which want to use IHubContext
can now receive it as constructor parameter or as property. But we have to tell container which instance it should inject. This can be done in container configuration, in multiple ways
Constructor can use ResolvedParameter
to correctly select IHubContext
implementation
// 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");
}));
Property injection, is also a bit tricky. It is needed to resolve correct instance in OnActivated
callback, for example like this:
// 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"));
I did similar to yourself, which got it working in Owin for me
builder.RegisterInstance(config.Resolver).As<IDependencyResolver>();
builder.Update(container);
Then use this to get my hub
Resolve<IDependencyResolver>().Resolve<IConnectionManager>().GetHubContext<MyHub>();
Hope this helps others out there
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With