Storyteller.NET结合NServiceBus启动端点实例失败求助
我之前也碰到过类似的AppDomain隔离导致NServiceBus程序集扫描异常的问题,结合你的场景,咱们一步步拆解问题和解决方案:
问题背景
你通过Storyteller + StorytellerCsproj Runner搭建测试环境,用以下命令启动Storyteller Web应用:
"..\..\packages\StorytellerRunnerCsproj.4.2.0\tools\StorytellerRunner.exe" open "..\..\MyTestProject" --culture en-US --app-domain pause
应用会在独立AppDomain中加载项目代码,但在执行var endpointInstance = await Endpoint.Start(endpointConfiguration);时抛出异常,而这段代码在普通控制台应用中完全正常。
错误详情
抛出的异常信息如下:
System.AggregateException: One or more errors occurred. ---> System.Exception: Can't find any behaviors/connectors for the root context (NServiceBus.Pipeline.ITransportReceiveContext) at NServiceBus.PipelineModelBuilder.Build() at NServiceBus.StepRegistrationsCoordinator.BuildPipelineModelFor[TRootContext]() at NServiceBus.Pipeline`1..ctor(IBuilder builder, ReadOnlySettings settings, PipelineModifications pipelineModifications) at NServiceBus.StartableEndpoint.<Start>d__1.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at NServiceBus.Endpoint.<Start>d__1.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult() at QPark.Cloud.Testing.Shared.Messaging.MessageService.<StartEndpointAsync>d__5.MoveNext() in C:\tfs\git\Repos\SystemTests\QPark.Cloud.SystemTests\QPark.Cloud.Testing.Shared\Messaging\MessageService.cs:line 49 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
问题根源
你的怀疑完全正确:独立AppDomain的程序集加载机制和普通控制台应用不同。NServiceBus启动时会自动扫描当前AppDomain中的程序集来构建管道行为,但Storyteller的独立AppDomain可能没有加载NServiceBus核心依赖或你的自定义程序集,导致管道构建时找不到ITransportReceiveContext对应的行为/连接器。
解决方案建议
1. 显式指定NServiceBus要扫描的程序集
默认的自动扫描在隔离AppDomain中容易遗漏程序集,手动指定需要扫描的程序集可以解决这个问题:
var endpointConfiguration = new EndpointConfiguration("YourEndpointName"); // 显式添加必须扫描的程序集,根据你的实际依赖调整 endpointConfiguration.AssembliesToScan( typeof(ITransportReceiveContext).Assembly, // NServiceBus核心程序集 typeof(YourMessageType).Assembly, // 你的消息/处理程序所在程序集 typeof(YourCustomBehavior).Assembly, // 如果有自定义管道行为的话 typeof(Transport).Assembly // 你使用的传输层(比如RabbitMQ、SQL Server等) );
2. 提前加载必要的程序集
在启动Endpoint前,手动加载NServiceBus相关的依赖程序集,确保它们被加载到当前AppDomain中:
// 提前加载核心依赖,根据你的NuGet包调整版本和名称 Assembly.Load("NServiceBus.Core, Version=7.0.0.0, Culture=neutral, PublicKeyToken=9fc386479f8a226c"); Assembly.Load("NServiceBus.Transport.RabbitMQ, Version=7.0.0.0, Culture=neutral, PublicKeyToken=9fc386479f8a226c"); // 加载你的自定义程序集 Assembly.LoadFrom(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "QPark.Cloud.Testing.Shared.dll"));
3. 调整Storyteller的AppDomain加载设置
检查Storyteller Runner的启动参数,尝试禁用影子复制(Shadow Copy)(如果支持的话)。影子复制会将程序集复制到临时目录加载,可能导致NServiceBus找不到正确的依赖路径。你可以查看Storyteller文档,看是否有相关参数可以调整。
4. 验证AppDomain中的程序集加载情况
在启动Endpoint前添加一段调试代码,输出当前AppDomain加载的所有程序集,确认NServiceBus相关程序集都已加载:
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { Console.WriteLine($"Loaded assembly: {assembly.FullName}"); }
运行后检查输出,确保NServiceBus.Core、传输层程序集以及你的业务程序集都在列表中。
5. 启用NServiceBus日志排查扫描过程
启用NServiceBus的控制台日志,查看程序集扫描的详细过程,确认是否遗漏了关键类型:
endpointConfiguration.UseLogging(l => l.LogToConsole()); endpointConfiguration.EnableInstallers();
启动后观察日志,搜索Scanning相关的条目,看是否扫描到了包含ITransportReceiveContext行为的程序集。
内容的提问来源于stack exchange,提问作者bliulinx

