【问题标题】:Inject SignalR IHubContext into controller with Autofac使用 Autofac 将 SignalR IHubContext 注入控制器
【发布时间】:2025-08-21 06:00:02
【问题描述】:

我正在尝试将 SignalR IHubContext 注入 ASP.NET MVC 5 应用程序框架 4.72(不是 .NET Core)中的 Web API 2.x 控制器。调用Web API控制器MyController时抛出此异常:

尝试创建类型为“MyController”的控制器时发生错误。确保控制器有一个无参数的公共构造函数

内部异常说:

无法使用可用的服务和参数调用类型为“MyController”的“Autofac.Core.Activators.Reflection.DefaultConstructorFinder”的构造函数:无法解析参数“Microsoft.AspNet.SignalR.IHubContext[MyHub] context' of constructor 'Void .ctor(Microsoft.AspNet.SignalR.IHubContext [ MyHub])'。

我不介意使用属性注入来执行此操作,但没有任何运气让它发挥作用。所以我正在注入控制器的c'tor。

我已按照以下答案寻求帮助:

这是 Web API 控制器:

public class MyController : WebApiController
{
    public IHubContext<MyHub> Context { get; set; }

    public MyController(IHubContext<MyHub> context)
    {
        Context = context;
    }   
}

这是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);
    });
}

我错过了什么?谢谢。

【问题讨论】:

    标签: c# asp.net asp.net-web-api dependency-injection autofac


    【解决方案1】:

    您的第一个问题是typeof(IHubContext)typeof(IHubContext&lt;MyHub&gt;) 不同。您可以使用以下方法解决此问题:

    pi.ParameterType == typeof(IHubContext).MakeGenericType(typeof(MyHub))

    但是,旧版本的 SignalR 不能很好地支持通用接口,因此如果您保持比较不变,并在 MyController 中注入 IHubContext 而不是 IHubContext&lt;MyHub&gt;,它可能会更好。

    【讨论】:

    • 谢谢,布拉德利。一个问题:传递到控制器的上下文没有找到传递给控制器​​上的操作的连接 ID。换句话说,当我调用Context.Clients.Client(connectionId).doSomething(); 时,它对客户端没有任何作用。好像注入的上下文和页面使用的上下文不同。
    • 这是IHubContext 的限制:它不知道调用者(*.com/a/50394456/177416)。一种解决方法:使用组发送消息。使用OnConnected 将用户名添加到一组;然后在 Web API 方法中,使用相同的用户名调用该组上的客户端函数
    • 找到解决方案:将 Web api 操作逻辑移至集线器上的方法。现在调用它,一切都很好!