Rebus,从异步处理程序创建 AppDomain/实例时出现异常 [英] Rebus, exception when creating AppDomain / Instance from async Handler
问题描述
我们对旧版本不存在的新(异步)版本的 Rebus 存在问题.
We have a problem with the new (async) version of Rebus that didn’t exist with the older version.
在处理 rebus 消息并尝试创建 AppDomain 和 Instance 以动态运行插件代码时,它总是给我一个异常.为了让例子尽可能简单,我做了一个测试方法:
When handling rebus message and trying to create AppDomain and Instance to run plugin code dynamically, it always give me an exception. To make the example as simple as possible, I made a Test method:
public static void Test()
{
AppDomain ad = AppDomain.CreateDomain("Test");
Loader loader = (Loader)ad.CreateInstanceAndUnwrap(typeof(Loader).Assembly.FullName, typeof(Loader).FullName);
}
class Loader : MarshalByRefObject
{
}
当我从普通"代码调用该方法时,它可以工作,但是当我从(异步)Rebus 消息处理方法调用它时,它给出了一个异常:
When I’m calling the method from ‘normal’ code it works but when I’m calling it from (async) Rebus message Handle method, it gives an exception:
System.Runtime.Serialization.SerializationException 被捕获
HResult=-2146233076 消息=类型程序集Rebus"中的Rebus.Transport.DefaultTransactionContext",Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' 未标记作为可序列化.源 = mscorlib 堆栈跟踪:在 System.AppDomain.CreateInstanceAndUnwrap(String assemblyName, String typeName)在 App.Bus.MessageParse.Process.Test() 在 d:\Project\App.Bus.MessageParser\Process.cs:line 45在 App.Bus.MessageParse.Process.d__0.MoveNext() 在 d:\Project\App.Bus.MessageParser\Process.cs:line 28 InnerException:
System.Runtime.Serialization.SerializationException was caught
HResult=-2146233076 Message=Type 'Rebus.Transport.DefaultTransactionContext' in assembly 'Rebus, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable. Source=mscorlib StackTrace: at System.AppDomain.CreateInstanceAndUnwrap(String assemblyName, String typeName) at App.Bus.MessageParse.Process.Test() in d:\Project\App.Bus.MessageParser\Process.cs:line 45 at App.Bus.MessageParse.Process.d__0.MoveNext() in d:\Project\App.Bus.MessageParser\Process.cs:line 28 InnerException:
对这个问题有什么想法吗?
Any idea about the problem?
推荐答案
Rebus 将其事务上下文存储在 AmbientTransactionContext.Current
中,该上下文由线程的逻辑调用上下文支持,当线程的逻辑调用上下文时,它会自动流向延续你等待
某事.
Rebus stores its transaction context in AmbientTransactionContext.Current
, which is backed by the thread's logical call context, which automatically flows to continuations when you await
something.
它也流向创建的应用程序域,显然;)
It flows to created appdomains as well, apparently ;)
我可以将 DefaultTransactionContext 标记为可序列化,但我担心您会得到一个异常,告诉您事务上下文字典中的项目不可序列化.
I could mark the DefaultTransactionContext as serializable, but I fear that you would then just get an exception telling you that the items in the transaction context's dictionary are not serializable.
我无法使事务上下文真正可序列化并保证它可以工作,因此 - 如果您需要在消息处理程序中创建一个应用程序域 - 我建议您暂时删除环境事务上下文 - 只记得把它又回来了:)
There is no way I can make the transaction context truly serializable and guarantee that it would work, so - if you need to create an appdomain in a message handler - I suggest you temporarily remove the ambient transaction context - just remember to put it back again :)
类似以下的内容应该可以解决问题:
Something like the following should do the trick:
public async Task Handle(SomeMessage message)
{
var transactionContext = AmbientTransactionContext.Current;
AmbientTransactionContext.Current = null;
try
{
JuggleWithAppDomainsInHere();
}
finally
{
AmbientTransactionContext.Current = transactionContext;
}
}
如果您的应用程序中使用 appdomains 进行操作是一种常见模式,我建议您将removing-and-restoring-of-the-ambient-Rebus-transaction"包装在 IDisposable
中,所以你可以
If it's a common pattern in your app that you do stuff with appdomains, I suggest you wrap the "removing-and-restoring-of-the-ambient-Rebus-transaction" in something IDisposable
, so you can
using(new DismantleAmbientRebusStuff())
{
JuggleWithAppDomainsInHere();
}
这篇关于Rebus,从异步处理程序创建 AppDomain/实例时出现异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!