I'm trying to inject a SignalR IHubContext
into a Web API 2.x controller in an ASP.NET MVC 5 app Framework 4.72 (not .NET Core). It's throwing this exception when calling the Web API controller MyController
:
An error occurred when trying to create a controller of type 'MyController'. Make sure that the controller has a parameterless public constructor
The inner exception says:
None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'MyController' can be invoked with the available services and parameters: Cannot resolve parameter 'Microsoft.AspNet.SignalR.IHubContext
[MyHub] context' of constructor 'Void .ctor(Microsoft.AspNet.SignalR.IHubContext
[MyHub])'.
I don't mind doing this using property injection but haven't had any luck getting that to work. So I'm doing injection into the c'tor of the controller.
I've followed these answers for help:
Here's the Web API controller:
public class MyController : WebApiController
{
public IHubContext<MyHub> Context { get; set; }
public MyController(IHubContext<MyHub> context)
{
Context = context;
}
}
And here's the pertinent part of the Startup.cs
:
public void Configuration(IAppBuilder app)
{
// Other code...
var builder = new ContainerBuilder();
var config = new HttpConfiguration();
builder.RegisterHubs(Assembly.GetExecutingAssembly());
builder.RegisterControllers(typeof(MvcApplication).Assembly)
.InstancePerRequest();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly())
.InstancePerRequest();
builder.RegisterType<AutofacDependencyResolver>()
.As<IDependencyResolver>()
.SingleInstance();
builder
.Register(c => c.Resolve<IConnectionManager>().GetHubContext<MyHub>())
.Named<IHubContext>("MyHub");
builder.RegisterType<MyController>()
.WithParameter(
new ResolvedParameter(
(pi, ctx) => pi.ParameterType == typeof(IHubContext),
(pi, ctx) => ctx.ResolveNamed<IHubContext>("MyHub")
)
);
var container = builder.Build();
app.UseAutofacMiddleware(container);
DependencyResolver.SetResolver(new Autofac.Integration.Mvc.AutofacDependencyResolver(container));
config.DependencyResolver = new AutofacWebApiDependencyResolver((IContainer)container);
app.Map("/signalr", map =>
{
var hubConfiguration = new HubConfiguration
{
Resolver = new AutofacDependencyResolver(container),
};
map.RunSignalR(hubConfiguration);
});
}
What am I missing? Thanks.
Your first problem is that typeof(IHubContext)
is not the same as typeof(IHubContext<MyHub>)
. You can get around that by using:
pi.ParameterType == typeof(IHubContext).MakeGenericType(typeof(MyHub))
However, old versions of SignalR don't support the generic interfaces very well, so it would probably work better if you left the comparison as is, and inject an IHubContext
rather than an IHubContext<MyHub>
in MyController
.