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();
}