我们遇到了Rebus的新(异步)版本的问题,而旧版本不存在此问题。

当处理重传消息并尝试创建AppDomain和Instance来动态运行插件代码时,它总是给我一个例外。
为了使示例尽可能简单,我制作了一个Test方法:

public static void Test()
{
    AppDomain ad = AppDomain.CreateDomain("Test");
    Loader loader = (Loader)ad.CreateInstanceAndUnwrap(typeof(Loader).Assembly.FullName, typeof(Loader).FullName);
}

class Loader : MarshalByRefObject
{
}


当我从“普通”代码中调用该方法时,它可以工作,但是当我从(异步)重传消息处理方法中调用时,它会给出一个例外:


  捕获了System.Runtime.Serialization.SerializationException
  HResult = -2146233076消息=类型
  程序集“ Rebus”中的“ Rebus.Transport.DefaultTransactionContext”,
  版本= 1.0.0.0,文化=中性,PublicKeyToken =空'未标记
  作为可序列化的。来源= mscorlib StackTrace:
         在System.AppDomain.CreateInstanceAndUnwrap(String assemblyName,String typeName)
         在d:\ Project \ App.Bus.MessageParser \ Process.cs:第45行的App.Bus.MessageParse.Process.Test()中
         在d:\ Project \ App.Bus.MessageParser \ Process.cs:第28行的App.Bus.MessageParse.Process.d__0.MoveNext()中


对这个问题有任何想法吗?

最佳答案

Rebus将其事务上下文存储在AmbientTransactionContext.Current中,该上下文由线程的逻辑调用上下文支持,当您对await进行某些操作时,该上下文自动流向继续。

显然,它也流到创建的应用程序域;)

我可以将DefaultTransactionContext标记为可序列化,但是我担心您随后会得到一个异常,告诉您事务上下文字典中的项目不可序列化。

我无法使事务上下文真正实现可序列化并保证它可以正常工作,因此-如果您需要在消息处理程序中创建一个appdomain-我建议您暂时删除环境事务上下文-请记住再次将其放回:)

如下所示的方法可以解决问题:

public async Task Handle(SomeMessage message)
{
    var transactionContext = AmbientTransactionContext.Current;
    AmbientTransactionContext.Current = null;
    try
    {
        JuggleWithAppDomainsInHere();
    }
    finally
    {
        AmbientTransactionContext.Current = transactionContext;
    }
}


如果您在应用程序中使用appdomains做事是一种常见的模式,我建议您将“删除和恢复环境Rebus事务”包装在IDisposable中,这样就可以

using(new DismantleAmbientRebusStuff())
{
    JuggleWithAppDomainsInHere();
}

10-05 18:12