【问题标题】:Trouble configuring SignalR in owin hosted Nancy app, plus MassTransit在 owin 托管的 Nancy 应用程序以及 MassTransit 中配置 SignalR 时遇到问题
【发布时间】:2017-07-31 22:11:00
【问题描述】:

尝试设置 SignalR 集线器(规范聊天)以在 OWIN 托管的 Nancy 应用和 MassTransit 中运行。 MassTransit 部分有效:

public ChatMessageConsumer(IEnumerable<IChatMessageProcessor> messageProcessors,
    IChatHub chatHub, 
    ILogger logger) { ... }

public async Task Consume(ConsumeContext<IChatMessage> context)
{
    _chatHub.BroadcastMessage( ... );
}

那些由 MassTransit 事件触发的消息会到达我的浏览器客户端。从客户端触发的那些永远不会这样做:

public class ChatHub : Hub, IChatHub 
{
    public ChatHub(ILifetimeScope lifetimeScope) 
    {
        _hubLifetimeScope = lifetimeScope.BeginLifetimeScope();
        // snip ...
    }
    // snip ...
}

public void Send(string name, string message)
{
    // publish message on bus
    _bus.Publish<IChatMessage>(/* snip ... */);

    _hubInstanceContext.Clients.All.BroadcastMessage(/* ... */);
}

public void BroadcastMessage(string service, string message, string correlationId) { /* snip ... */ }

据我所知,该框架正在寻找一个无参数的构造函数,而我没有(而且显然不想要)。在我的启动中,我创建了一个配置,将 Autofac 解析器注册为依赖解析器,并使用该配置启动 SignalR。 Nancy 使用具有相同容器的 Autofac 引导程序启动。

public void Configuration(IAppBuilder app)
{
    var container = ResolveDependencies();
    var hubConfiguration = new HubConfiguration
    {
        EnableDetailedErrors = true,
        Resolver = container.Resolve<IDependencyResolver>()
    };

    app.UseAutofacMiddleware(container);
    app.MapSignalR(hubConfiguration);
    app.Map("/site", sb => sb.UseNancy(options => options.Bootstrapper = new ChatBootstrapper(container)));
    // snip MassTransit bus start/stop, etc. ...
}

static IContainer ResolveDependencies()
{
    var builder = new ContainerBuilder();

    // snip MassTransit consumers, etc. ...

    builder.RegisterType<ChatHub>().As<IChatHub>().ExternallyOwned().SingleInstance();
    builder.RegisterType<AutofacDependencyResolver>().As<IDependencyResolver>().SingleInstance();
    builder.Register(i => i.Resolve<IDependencyResolver>()
            .Resolve<IConnectionManager>()
            .GetHubContext<ChatHub, IChatHub>())
        .SingleInstance()
        .ExternallyOwned();
    // snip Logger registrations, etc. ...
}

Nancy 正在工作(这就是我将事件发布到 MassTransit 的方式)。 MassTransit 正在工作——事件被消耗并且能够广播客户端接收到的 SignalR 事件。 SignalR 部分工作——我显然已经连接到集线器,因为我可以接收来自 MassTransit 消费者的消息广播,但是当我尝试从客户端发送消息时,我收到 500 内部服务器错误。如果我向集线器添加一个无参数构造函数,当我尝试从客户端发送时,会调用该构造函数,导致我认为我为 SignalR 设置 Autofac 的方式有问题。在这种情况下,当调用Send 方法时,应该在构造函数中通过DI 设置的_hubInstanceContext_bus 成员为空。我尝试按照https://stackoverflow.com/a/36476106/173225 中的建议添加IHubContext&lt;IMyHub&gt; 属性,但从未设置过,这支持了我的怀疑,即在这种情况下根本没有使用DI。

我已经查看了 Autofac 文档、关于 SO 的许多问题和几篇博客文章,但看不出我可能遗漏了什么。我还应该注意,在将 Autofac 添加到组合之前,我确实让客户端聊天正常工作(即我可以send 一条消息并接收broadcastMessage)。

有什么建议吗?

编辑:在无参数构造函数中添加调用堆栈:

>   Chat.Service.exe!Chat.Service.Hubs.ChatHub.ChatHub() Line 25    C#
    mscorlib.dll!System.Activator.CreateInstance(System.Type type, bool nonPublic)  Unknown
    mscorlib.dll!System.Activator.CreateInstance(System.Type type)  Unknown
    Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.Hubs.DefaultHubActivator.Create(Microsoft.AspNet.SignalR.Hubs.HubDescriptor descriptor) Line 29  C#
    Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.Hubs.DefaultHubManager.ResolveHub(string hubName) Line 89    C#
    Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.Hubs.HubDispatcher.CreateHub(Microsoft.AspNet.SignalR.IRequest request, Microsoft.AspNet.SignalR.Hubs.HubDescriptor descriptor, string connectionId, Microsoft.AspNet.SignalR.Hubs.StateChangeTracker tracker, bool throwIfFailedToCreate) Line 455  C#
    Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.Hubs.HubDispatcher.OnReceived(Microsoft.AspNet.SignalR.IRequest request, string connectionId, string data) Line 180  C#
    Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.PersistentConnection.ProcessRequestPostGroupRead.AnonymousMethod__5() Line 282   C#
    Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.TaskAsyncHelper.FromMethod(System.Func<System.Threading.Tasks.Task> func) Line 771   C#
    Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.PersistentConnection.ProcessRequestPostGroupRead.AnonymousMethod__4(string data) Line 282    C#
    Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.Transports.ForeverTransport.ProcessSendRequest() Line 151    C#
    [Resuming Async Method] 
    mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(object stateMachine)  Unknown
    mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)   Unknown
    mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)   Unknown
    mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run()    Unknown
    Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.TaskAsyncHelper.RunWithPreservedCulture.AnonymousMethod__72_0(System.Action f) Line 1036 C#
    Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.TaskAsyncHelper.RunWithPreservedCulture.AnonymousMethod__71_0(System.Action<System.__Canon> f, System.__Canon state) Line 1028   C#
    Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.TaskAsyncHelper.RunWithPreservedCulture<System.__Canon, System.__Canon, System.__Canon>(Microsoft.AspNet.SignalR.TaskAsyncHelper.CulturePair preservedCulture, System.Func<System.__Canon, System.__Canon, System.__Canon> func, System.__Canon arg1, System.__Canon arg2) Line 1009 C#
    Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.TaskAsyncHelper.RunWithPreservedCulture<System.Action>(Microsoft.AspNet.SignalR.TaskAsyncHelper.CulturePair preservedCulture, System.Action<System.Action> action, System.Action arg) Line 1031  C#
    Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.TaskAsyncHelper.RunWithPreservedCulture(Microsoft.AspNet.SignalR.TaskAsyncHelper.CulturePair preservedCulture, System.Action action) Line 1037   C#
    Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.TaskAwaiterHelper.PreserveCultureUnsafeOnCompleted.AnonymousMethod__0() Line 48  C#
    mscorlib.dll!System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Action action, bool allowInlining, ref System.Threading.Tasks.Task currentTask)    Unknown
    mscorlib.dll!System.Threading.Tasks.Task.FinishContinuations()  Unknown
    mscorlib.dll!System.Threading.Tasks.Task.FinishStageThree() Unknown
    mscorlib.dll!System.Threading.Tasks.Task<System.__Canon>.TrySetResult(System.__Canon result)    Unknown
    mscorlib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder<Microsoft.AspNet.SignalR.Hosting.INameValueCollection>.SetResult(Microsoft.AspNet.SignalR.Hosting.INameValueCollection result)  Unknown
    Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.Owin.ServerRequest.ReadForm() Line 111   C#
    [Resuming Async Method] 
    mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(object stateMachine)  Unknown
    mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)   Unknown
    mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)   Unknown
    mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run()    Unknown
    Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.TaskAsyncHelper.RunWithPreservedCulture.AnonymousMethod__72_0(System.Action f) Line 1036 C#
    Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.TaskAsyncHelper.RunWithPreservedCulture.AnonymousMethod__71_0(System.Action<System.__Canon> f, System.__Canon state) Line 1028   C#
    Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.TaskAsyncHelper.RunWithPreservedCulture<System.__Canon, System.__Canon, System.__Canon>(Microsoft.AspNet.SignalR.TaskAsyncHelper.CulturePair preservedCulture, System.Func<System.__Canon, System.__Canon, System.__Canon> func, System.__Canon arg1, System.__Canon arg2) Line 1009 C#
    Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.TaskAsyncHelper.RunWithPreservedCulture<System.Action>(Microsoft.AspNet.SignalR.TaskAsyncHelper.CulturePair preservedCulture, System.Action<System.Action> action, System.Action arg) Line 1031  C#
    Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.TaskAsyncHelper.RunWithPreservedCulture(Microsoft.AspNet.SignalR.TaskAsyncHelper.CulturePair preservedCulture, System.Action action) Line 1037   C#
    Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.TaskAwaiterHelper.PreserveCultureUnsafeOnCompleted.AnonymousMethod__0() Line 48  C#
    mscorlib.dll!System.Threading.Tasks.AwaitTaskContinuation.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()    Unknown
    mscorlib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch()    Unknown
    mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() Unknown
    [Async Call]    
    Microsoft.Owin.dll!Microsoft.Owin.Mapping.MapMiddleware.Invoke(System.Collections.Generic.IDictionary<string, object> environment) Line 64  C#
    [Async Call]    
    Autofac.Integration.Owin.dll!Owin.AutofacAppBuilderExtensions.RegisterAutofacLifetimeScopeInjector.AnonymousMethod__0(Microsoft.Owin.IOwinContext context, System.Func<System.Threading.Tasks.Task> next) Line 333  C#
    [Async Call]    
    Microsoft.Owin.Host.HttpListener.dll!Microsoft.Owin.Host.HttpListener.OwinHttpListener.ProcessRequestAsync(System.Net.HttpListenerContext context) Line 262 C#
    [Async Call]    
    Microsoft.Owin.Host.HttpListener.dll!Microsoft.Owin.Host.HttpListener.OwinHttpListener.ProcessRequestsAsync() Line 244  C#

【问题讨论】:

  • 您是否安装并初始化了 Autofac SignalR 集成?
  • 您的意思是Install-Package Autofac.SignalR 然后关注docs.autofac.org/en/latest/integration/…? AFAIK 我已按照文档中的说明进行操作。这就是为什么我包含了我的启动 Configuration 代码,以防我错过了什么。
  • 你有任何堆栈跟踪吗?如果没有,您能否在无参数构造函数上添加一个断点并共享完整的调用堆栈?
  • 您能检查一下config.Resolver 是不是正确的(即AutofacDependencyResolver)?
  • hubConfiguration.Resolver.GetType() 产生{Name = "AutofacDependencyResolver" FullName = "Autofac.Integration.SignalR.AutofacDependencyResolver"}

标签: signalr owin autofac nancy masstransit


【解决方案1】:

我需要改变:

builder.RegisterType<ChatHub>().As<IChatHub>().ExternallyOwned().SingleInstance();

到:

builder.RegisterType<ChatHub>().ExternallyOwned();
builder.Register(c => c.Resolve<ChatHub>()).As<IChatHub>();

此时我不完全确定原因,但我将在 Autofac 源代码中进行一些挖掘并更新此答案。

我之前尝试过许多变体,有和没有SingleInstanceAsImplementedInterfaces 等,但是直到我将它剥离回完全Autofac docs 中呈现的内容之前都没有任何效果。

【讨论】:

    猜你喜欢
    • 2021-12-27
    • 2021-05-09
    • 1970-01-01
    • 2019-11-24
    • 2013-07-09
    • 1970-01-01
    • 2019-11-26
    • 2016-10-06
    • 2015-12-11
    相关资源
    最近更新 更多