Rebus, exception when creating AppDomain / Instance from async Handler

南笙酒味 提交于 2019-12-10 23:31:02

问题


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?


回答1:


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


来源:https://stackoverflow.com/questions/34021061/rebus-exception-when-creating-appdomain-instance-from-async-handler

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!