与Unity集成的SignalR上的PerRequestLifetimeManager相关的异常

时间:2016-04-27 09:45:46

标签: c# signalr unity-container

我现在有时会抛出以下异常,但我无法确定它何时发生,更重要的是,为什么。我敢打赌,它可能与我的依赖注入容器Unity以及我注册类型的方式有关。这是错误:

The PerRequestLifetimeManager can only be used in the context of an HTTP request. Possible causes for this error are using the lifetime manager on a non-ASP.NET application, or using it in a thread that is not associated with the appropriate synchronization context.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.InvalidOperationException: The PerRequestLifetimeManager can only be used in the context of an HTTP request. Possible causes for this error are using the lifetime manager on a non-ASP.NET application, or using it in a thread that is not associated with the appropriate synchronization context.

Source Error: 

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace: 


[InvalidOperationException: The PerRequestLifetimeManager can only be used in the context of an HTTP request. Possible causes for this error are using the lifetime manager on a non-ASP.NET application, or using it in a thread that is not associated with the appropriate synchronization context.]
   Microsoft.Practices.Unity.Mvc.UnityPerRequestHttpModule.GetDictionary(HttpContext context) +195
   Microsoft.Practices.Unity.Mvc.UnityPerRequestHttpModule.GetValue(Object lifetimeManagerKey) +50
   Microsoft.Practices.ObjectBuilder2.LifetimeStrategy.PreBuildUp(IBuilderContext context) +146
   Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context) +396
   Microsoft.Practices.ObjectBuilder2.BuilderContext.NewBuildUp(NamedTypeBuildKey newBuildKey) +130
   lambda_method(Closure , IBuilderContext ) +206
   Microsoft.Practices.ObjectBuilder2.<>c__DisplayClass1.<GetBuildMethod>b__0(IBuilderContext context) +33
   Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context) +337
   Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context) +396
   Microsoft.Practices.ObjectBuilder2.BuilderContext.NewBuildUp(NamedTypeBuildKey newBuildKey) +130
   lambda_method(Closure , IBuilderContext ) +206
   Microsoft.Practices.ObjectBuilder2.<>c__DisplayClass1.<GetBuildMethod>b__0(IBuilderContext context) +33
   Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context) +337
   Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context) +396
   Microsoft.Practices.ObjectBuilder2.BuilderContext.NewBuildUp(NamedTypeBuildKey newBuildKey) +130
   lambda_method(Closure , IBuilderContext ) +212
   Microsoft.Practices.ObjectBuilder2.<>c__DisplayClass1.<GetBuildMethod>b__0(IBuilderContext context) +33
   Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context) +337
   Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context) +396
   Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name, IEnumerable`1 resolverOverrides) +238

[ResolutionFailedException: Resolution of the dependency failed, type = "TradeForce.Portal.Hubs.ExecutionReportsHub", name = "(none)".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The PerRequestLifetimeManager can only be used in the context of an HTTP request. Possible causes for this error are using the lifetime manager on a non-ASP.NET application, or using it in a thread that is not associated with the appropriate synchronization context.
-----------------------------------------------
At the time of the exception, the container was:

  Resolving TradeForce.Portal.Hubs.ExecutionReportsHub,(none)
  Resolving parameter "iExecutionReportsBusiness" of constructor TradeForce.Portal.Hubs.ExecutionReportsHub(TradeForce.Dominio.Interfaces.Business.Reports.IExecutionReportsBusiness iExecutionReportsBusiness, TradeForce.Dominio.Interfaces.Repository.NH.IUsers iUsers, TradeForce.Dominio.Interfaces.Repository.NH.ICollaborators iCollaborators, TradeForce.Infraestrutura.Persistencia.NHibernateUtil.SessionProvider sessionProvider)
    Resolving TradeForce.Business.Entities.Reports.ExecutionReportsBusiness,(none) (mapped from TradeForce.Dominio.Interfaces.Business.Reports.IExecutionReportsBusiness, (none))
    Resolving parameter "iExecutionReports" of constructor TradeForce.Business.Entities.Reports.ExecutionReportsBusiness(TradeForce.Dominio.Interfaces.Repository.NH.Reports.IExecutionReports iExecutionReports)
      Resolving TradeForce.Infraestrutura.DAO.NH.Reports.DAOExecutionReports,(none) (mapped from TradeForce.Dominio.Interfaces.Repository.NH.Reports.IExecutionReports, (none))
      Resolving parameter "sessionProvider" of constructor TradeForce.Infraestrutura.DAO.NH.Reports.DAOExecutionReports(TradeForce.Infraestrutura.Persistencia.NHibernateUtil.SessionProvider sessionProvider)
        Resolving TradeForce.Infraestrutura.Persistencia.NHibernateUtil.SessionProvider,(none)
]
   Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name, IEnumerable`1 resolverOverrides) +500
   Microsoft.Practices.Unity.UnityContainer.Resolve(Type t, String name, ResolverOverride[] resolverOverrides) +20
   TradeForce.Portal.Helpers.UnityHubActivator.Create(HubDescriptor descriptor) +108
   Microsoft.AspNet.SignalR.Hubs.HubDispatcher.CreateHub(IRequest request, HubDescriptor descriptor, String connectionId, StateChangeTracker tracker, Boolean throwIfFailedToCreate) +601
   Microsoft.AspNet.SignalR.Hubs.HubDispatcher.OnReceived(IRequest request, String connectionId, String data) +614
   Microsoft.AspNet.SignalR.<>c__DisplayClassc.<ProcessRequestPostGroupRead>b__7() +41
   Microsoft.AspNet.SignalR.TaskAsyncHelper.FromMethod(Func`1 func) +25
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +181
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +69
   Microsoft.AspNet.SignalR.Transports.<ProcessSendRequest>d__12.MoveNext() +944
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +181
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +69
   Microsoft.Owin.Mapping.<Invoke>d__0.MoveNext() +599
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +181
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +69
   Microsoft.Owin.Mapping.<Invoke>d__0.MoveNext() +870
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +181
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +69
   Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.<RunApp>d__5.MoveNext() +203
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +181
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +69
   Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.<DoFinalWork>d__2.MoveNext() +193
   Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.StageAsyncResult.End(IAsyncResult ar) +96
   System.Web.AsyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +509
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +146

这里是使用Unity的SignalR中心:

public class ExecutionReportsHub : BaseHub
{
    private readonly IExecutionReportsBusiness _iExecutionReportsBusiness;
    private readonly IUsers _iUsers;
    private readonly ICollaborators _iCollaborators;
    private readonly SessionProvider _sessionProvider;

    public ExecutionReportsHub(IExecutionReportsBusiness iExecutionReportsBusiness, IUsers iUsers, ICollaborators iCollaborators, SessionProvider sessionProvider)
    {
        _iExecutionReportsBusiness = iExecutionReportsBusiness;
        _iUsers = iUsers;
        _iCollaborators = iCollaborators;
        _sessionProvider = sessionProvider;
    }

    // More code...
}

类型注册:

public class UnityConfig
{
    public static void RegisterTypes(IUnityContainer container)
    {
        container.RegisterInstance(new SessionFactoryProvider());
        container.RegisterType<SessionProvider>(new PerRequestLifetimeManager());

        container.RegisterType<IUsers, DAOUsers>();
        container.RegisterType<ICollaborators, DAOCollaborators>();
        container.RegisterType<IExecutionReportsBusiness, ExecutionReportsBusiness>();

        container.RegisterType<IHubActivator, UnityHubActivator>(new PerRequestLifetimeManager());
        container.RegisterType<ExecutionReportsHub, ExecutionReportsHub>(new ContainerControlledLifetimeManager());

        // Other unrelated types being registered...
    }
}

从客户端调用执行其中一个集线器方法时发生错误。

提前致谢。

1 个答案:

答案 0 :(得分:1)

我建议您控制集线器的生命周期。这是由管道管理的。

来自API指南:http://www.asp.net/signalr/overview/guide-to-the-api/hubs-api-guide-server#hubclass

  

您没有实例化Hub类或从您自己的方法调用其方法   服务器上的代码;所有这些都由SignalR Hubs为您完成   管道。 SignalR每次都会创建一个Hub类的新实例   它需要处理Hub操作,例如客户端连接时,   断开连接,或对服务器进行方法调用。

     

由于Hub类的实例是瞬态的,因此您无法使用它们   保持状态从一个方法调用到下一个。每一次   服务器接收来自客户端的方法调用,一个新的实例   Hub类处理消息。通过多重维持状态   连接和方法调用,使用一些其他方法,如a   数据库,或Hub类上的静态变量,或其他类   这不是来自Hub。如果您将数据保留在内存中,请使用   方法如Hub类上的静态变量,数据将是   应用程序域回收时丢失。

您仍然可以将HubActivatorLifeTimeManager一起使用。但是,当您尝试管理集线器的生命周期时,您可能会在一段时间后遇到意外行为。

使用PerRequestLifeTimeManager无法使用SignalR和集线器开箱即用。部分是因为HttpContext。它使用UnityPerRequestHttpModule,后者又使用HttpContext.Current

internal static void SetValue(object lifetimeManagerKey, object value)
{
  Dictionary<object, object> dictionary = UnityPerRequestHttpModule.GetDictionary(HttpContext.Current);
  if (dictionary == null)
  {
    dictionary = new Dictionary<object, object>();
    HttpContext.Current.Items[UnityPerRequestHttpModule.ModuleKey] = (object) dictionary;
  }
  dictionary[lifetimeManagerKey] = value;
}

并且HttpContext.Current在集线器中始终为空。您可以使用Context.Request.GetHttpContext()创建自己的实现。

但是,如果您确实需要管理集线器的生命周期,则可以创建HubContainer。当我们需要控制集线器时,我在一个项目中完成了这项工作。

public class HubActivator : IHubActivator
{
    private readonly IUnityContainer _container;
    private readonly IHubContainer<ExecutionReportsHub> _hubContainer;

    public HubActivator(IUnityContainer container)
    {
        _container = container;
        _hubContainer = container.Resolve<IHubContainer<ExecutionReportsHub>>();
    }

    public IHub Create(HubDescriptor descriptor)
    {
        object hub = _container.Resolve(descriptor.HubType) ?? Activator.CreateInstance(descriptor.HubType);
        if (hub is ExecutionReportsHub)
        {
            _hubContainer.Add(hub as ExecutionReportsHub);
        }
        return hub as IHub;
    }
}

public class ExecutionReportsHubContainer : IHubContainer<ExecutionReportsHub>
{
    public ExecutionReportsHubContainer()
    {
        _hubs = new List<ExecutionReportsHub>();
    }

    private  IList<ExecutionReportsHub> _hubs { get; set; }

    public void Add(ExecutionReportsHub hub)
    {
        _hubs.Add(hub);
    }

    public void Remove(ExecutionReportsHub hub)
    {
        _hubs.Remove(hub);
    }

    public void Dispose(string connectionId)
    {
        IEnumerable<ExecutionReportsHub> hubs = _hubs.Where(x => x.ConnectionId.Equals(connectionId)).ToList();
        foreach (var hub in hubs)
        {
            hub.Detach();
            Remove(hub);
            hub.Dispose();
        }
    }
}

public interface IHubContainer<T> where T : IHub
{
    void Dispose(string connectionId);
    void Remove(IFlowHub flowHub);
    void Add(IFlowHub flowHub);
}

您的注册:

unityContainer.RegisterType<IHubContainer<ExecutionReportsHub>, ExecutionReportsHubContainer >(new ContainerControlledLifetimeManager());
unityContainer.RegisterType<IHubActivator, HubActivator>(new ContainerControlledLifetimeManager())
相关问题