Rebus,从异步处理程序创建 AppDomain / 实例时出现异常
Rebus, exception when creating AppDomain / Instance from async Handler
旧版本不存在的 Rebus 新(异步)版本存在问题。
当处理 rebus 消息并尝试为 运行 插件代码动态创建 AppDomain 和实例时,它总是给我一个异常。
为了让例子尽可能简单,我做了一个测试方法:
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 消息处理方法调用它时,它给出了一个异常:
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:
对这个问题有什么想法吗?
Rebus 将其事务上下文存储在 AmbientTransactionContext.Current
中,它由线程的逻辑调用上下文支持,当您 await
某些内容时,它会自动流向延续。
它显然也流向创建的应用程序域 ;)
我可以将 DefaultTransactionContext 标记为可序列化,但我担心您会得到一个异常,告诉您事务上下文字典中的项目不可序列化。
我无法使事务上下文真正可序列化并保证它会工作,所以 - 如果您需要在消息处理程序中创建应用程序域 - 我建议您暂时删除环境事务上下文 - 请记住再放回去:)
像下面这样的东西应该可以解决问题:
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
中,这样您就可以
using(new DismantleAmbientRebusStuff())
{
JuggleWithAppDomainsInHere();
}
旧版本不存在的 Rebus 新(异步)版本存在问题。
当处理 rebus 消息并尝试为 运行 插件代码动态创建 AppDomain 和实例时,它总是给我一个异常。 为了让例子尽可能简单,我做了一个测试方法:
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 消息处理方法调用它时,它给出了一个异常:
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:
对这个问题有什么想法吗?
Rebus 将其事务上下文存储在 AmbientTransactionContext.Current
中,它由线程的逻辑调用上下文支持,当您 await
某些内容时,它会自动流向延续。
它显然也流向创建的应用程序域 ;)
我可以将 DefaultTransactionContext 标记为可序列化,但我担心您会得到一个异常,告诉您事务上下文字典中的项目不可序列化。
我无法使事务上下文真正可序列化并保证它会工作,所以 - 如果您需要在消息处理程序中创建应用程序域 - 我建议您暂时删除环境事务上下文 - 请记住再放回去:)
像下面这样的东西应该可以解决问题:
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
中,这样您就可以
using(new DismantleAmbientRebusStuff())
{
JuggleWithAppDomainsInHere();
}