OWIN + SignalR + Autofac

iti*_*tim 14 c# autofac signalr owin

摘自:http://docs.autofac.org/en/latest/integration/signalr.html:

"OWIN集成中的常见错误是使用GlobalHost.在OWIN中,您可以从头开始创建配置.在使用OWIN集成时,不应该在任何地方引用GlobalHost."

这听起来很合理.但是,如何IHubContext通过ApiController解析,就像通常的(非OWIN):

GlobalHost.ConnectionManager.GetHubContext<MyHub>()

我无法在任何地方找到这个参考,我现在唯一的方法是HubConfiguration在同一个容器中注册实例并执行此操作:

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

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

  // ...

}
Run Code Online (Sandbox Code Playgroud)

但是,这对我来说似乎相当冗长.这样做的正确方法是什么?更具体一点,是否有一种干净的注册方式IConnectionManager

编辑:

我最终做的是:

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);
Run Code Online (Sandbox Code Playgroud)

但我觉得必须有一种更简单的方法来IConnectionManager注入控制器.

Jam*_*all 15

这个答案有点迟了但是这里有.

  • 我推荐强类型集线器.
  • 您需要为强类型集线器添加特定注册.
  • 我不使用GlobalHost
    • 相反,我使用为OWIN注册创建的配置.

枢纽声明

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

[HubName("myHub")]
public class MyHub : Hub<IMyHub>
Run Code Online (Sandbox Code Playgroud)

集线器注册

来自您的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);
Run Code Online (Sandbox Code Playgroud)

在后台代码中解析集线器

使用AutoFacs AutowiredProperties()扩展方法然后它可以解析正确的上下文(如果你愿意,也可以在构造函数中).

public IHubContext<IMyHub> InstanceHubContext { get; [UsedImplicitly] set; }
Run Code Online (Sandbox Code Playgroud)

  • 谢谢.辉煌.我使用稍微修改过的解决方案:`builder.RegisterType <AutofacDependencyResolver>().作为<Microsoft.AspNet.SignalR.IDependencyResolver>().SingleInstance();``builder.Register(context => context.Resolve <Microsoft.AspNet. SignalR.IDependencyResolver>().解析<IConnectionManager>().GetHubContext <MyHub,IMyHub>()).ExternallyOwned();`并使用autofac解析解析器:`hubConfiguration.Resolver = container.Resolve <Microsoft.AspNet.SignalR .IDependencyResolver>();``httpConfiguration`的统一性相同. (3认同)

dra*_*rax 7

你可以做的是将一些重复的代码(我假设IHubContext也用于其他一些类,并以相同的方式提取)进入容器注册.

首先是注册IHubContext实例,我假设你在项目中有多个集线器.在这种情况下,服务必须注册为命名服务.

builder
    .Register<IHubContext>(c => c.Resolve<IConnectionManager>().GetHubContext<MyHub>())
    .Named<IHubContext>("MyHub");
Run Code Online (Sandbox Code Playgroud)

想要使用的类IHubContext现在可以作为构造函数参数或属性接收它.但是我们必须告诉容器它应该注入哪个实例.这可以通过多种方式在容器配置中完成

构造函数可以ResolvedParameter用来正确选择IHubContext实现

// 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");
    }));
Run Code Online (Sandbox Code Playgroud)

物业注入,也有点棘手.需要在OnActivated回调中解析正确的实例,例如:

// 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"));
Run Code Online (Sandbox Code Playgroud)