Rebus,从异步处理程序创建AppDomain/实例时发生异常 [英] Rebus, exception when creating AppDomain / Instance from async Handler

查看:112
本文介绍了Rebus,从异步处理程序创建AppDomain/实例时发生异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们遇到了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:line 28中的App.Bus.MessageParse.Process.d__0.MoveNext()处28 InnerException:

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

解决方案

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

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

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

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

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

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

如果在您的应用程序中有一个常见的模式是您处理appdomain,我建议您将删除和恢复环境Rebus事务"包装在IDisposable中,这样您就可以

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

We have a problem with the new (async) version of Rebus that didn’t exist with the older version.

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
{
}

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

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

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆