将Autofac与SignalR一起使用时出现作用域错误



我正试图在SignalR集线器中注入HttpContextBase

public class EventHub : Hub, IDisconnect
{
private readonly HttpContextBase _httpContextBase;
public EventHub(HttpContextBase httpContextBase)
{
_httpContextBase = httpContextBase;
}
[...]
}

注册代码如下:

private static void InitAutofac()
{
var builder = new ContainerBuilder();
var assembly = typeof (MvcApplication).Assembly;
builder.RegisterControllers(assembly).PropertiesAutowired();
builder.RegisterModule(new AutofacWebTypesModule());
builder.RegisterFilterProvider();
builder.RegisterAssemblyTypes(assembly)
.Where(InterfaceBasedInjectedClasses())
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
builder.RegisterAssemblyTypes(assembly)
.Where(InterfaceLessInjectedClasses())
.InstancePerLifetimeScope();
builder.RegisterType<SurvivalContainer>().InstancePerLifetimeScope();
builder.RegisterType<EventHub>().InstancePerLifetimeScope();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

GlobalHost.DependencyResolver = new SignalR.Autofac.AutofacDependencyResolver(container);
RouteTable.Routes.MapHubs();
}

我得到的错误是:

[DependencyResolutionException:没有与Tag匹配的作用域"httpRequest"在实例所在的作用域中可见请求。这通常表示注册为SingleInstance()组件正在请求每个HTTP请求(或类似的场景。)web下的集成总是要求DependencyResolver.Current或ILifetimeScopeProvider.RequestLifetime,从不来自容器本身。]

Stacktrace:

Autofac.Core.Lifetime.MatchingScopeLifetime.FindScope(ISharingLifetimeScope mostNestedVisibleScope) +160
Autofac.Core.Resolving.InstanceLookup..ctor(IComponentRegistration registration, IResolveOperation context, ISharingLifetimeScope mostNestedVisibleScope, IEnumerable`1 parameters) +57
Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters) +102
Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters) +64
Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters) +164
Autofac.Core.Container.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters) +14
Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance) +70
Autofac.ResolutionExtensions.TryResolve(IComponentContext context, Type serviceType, Object& instance) +70
SignalR.Autofac.AutofacDependencyResolver.GetService(Type serviceType) in D:etcDevSignalR.AutofacAutofacDependencyResolver.cs:30
SignalR.Hubs.DefaultHubActivator.Create(HubDescriptor descriptor) +60
SignalR.Hubs.DefaultHubManager.ResolveHub(String hubName) +27
SignalR.Hubs.HubDispatcher.CreateHub(IRequest request, HubDescriptor descriptor, String connectionId, TrackingDictionary state, Boolean throwIfFailedToCreate) +445
SignalR.Hubs.HubDispatcher.OnReceivedAsync(IRequest request, String connectionId, String data) +246
SignalR.<>c__DisplayClass6.<ProcessRequestAsync>b__4(String data) +29
SignalR.Transports.ForeverTransport.ProcessSendRequest() +63
SignalR.Transports.ForeverTransport.ProcessRequestCore(ITransportConnection connection) +70
SignalR.Transports.ForeverTransport.ProcessRequest(ITransportConnection connection) +5
SignalR.PersistentConnection.ProcessRequestAsync(HostContext context) +560
SignalR.Hubs.HubDispatcher.ProcessRequestAsync(HostContext context) +120
SignalR.Hosting.AspNet.AspNetHandler.ProcessRequestAsync(HttpContextBase context) +422       SignalR.Hosting.AspNet.HttpTaskAsyncHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +68
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +301
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

我刚开始使用autofac和SignalR,我发现自己有点卡住了。关于SO的相关主题都没有帮助。你知道我做错了什么吗?

问题是这一行:

builder.RegisterModule(new AutofacWebTypesModule());

异常消息表示,在解析过程中,正在尝试从标记为httpRequest的生存期作用域中解析某些内容。当你注册InstancePerHttpRequest():时,你会在Autofac中获得这样的注册

// These two are roughly equivalent:
builder.RegisterType<SomeType>().InstancePerHttpRequest();
builder.RegisterType<SomeType>().InstancePerMatchingLifetimeScope("AutofacWebRequest");

如果您查看AutofacWebTypesModule的源代码,它会将web抽象(如您要查找的HttpContextBase)注册为InstancePerHttpRequest

此外,如果您查看Autofac.Integration.Mvc.AutofacDependencyResolver的工作方式,无论何时在请求期间解析类型,它都会创建一个新的、嵌套的、命名的、带有httpRequest标记的生存期作用域。这让你拥有了神奇的InstancePerHttpRequest

假设您使用的SignalR.Autofac库就是这里的库,也是NuGet上的库),在SignalR.Autofac.AutofacDependencyResolver中查找时,没有为服务解析创建这样的嵌套/命名生存期范围。

因此,当Autofac试图解析HttpContextBase依赖项时,它找不到httpRequest标记的作用域(因为它不存在),并发出您看到的错误。

对此没有简单的答案。嵌套的httpRequest作用域实际上很重要,因为它基本上不可能存在于真实web请求的之外。它使它变得"安全"——如果没有web上下文(比如在应用程序启动时),就无法获得HttpContextBase

如果你需要注入一个HttpContextBase,并且你确信你的EventHub只适用于一个网络请求,就这样(我不是SignalR,所以请耐心等待),这意味着你要么需要:

  • 请SignalR.Autofac项目对此进行修复
  • 实现您自己的自定义SignalR.Autofac.AutofacDependencyResolver,它以MVC解析器的方式处理事情

如果不亲自做这项工作并进行测试,我就无法真正提供如何完成这项工作的具体指导<这个练习留给读者>

最新更新