.NET : execute some non-thread-safe code without issue in parallel with AppDomains

, , Comments Off on .NET : execute some non-thread-safe code without issue in parallel with AppDomains

Today I faced a specific need withing a WPF application: I have a well-tested and already in production code which works well for a given user and I need to create an application to execute the same “one-thread/context” code for a lot of users at the same time. The code uses a lot of static fields, properties and can’t be run as it is in different threads.

The solution I ended up with is to create an AppDomain by “worker” and to execute the already existing code in each one. The context will be unique in each AppDomain and I will be able to reuse my existing code.

To have this working I have to perform these steps:

  • Create a new class project “MaDllAPart” on which I add a reference to my existing code assembly.
  • Create a new class “StartPoint” in it which inherits from MarshalByRefObject. This will let it be called from another AppDomain (my new WPF application in this case).
  • Add an “Execute” Method to my StartPoint class which calls my legacy code.
  • Create an AppDomain by thread, instanciate a StartPoint in this AppDomain.
  • Instanciate a StartPoint in this AppDomain and call it’s Execute method.

structure

The code for the StartPoint class is very easy :

public class MonPointDentree : MarshalByRefObject
{
    public static string Context;

    public void Execute(string input)
    {
        // Task can't be marshalled : let's wait
        ExecuteAsync(input).Wait();
    }

    private async Task ExecuteAsync(string input)
    {
        Debug.WriteLine("[BEFORE] " + Context);
        Context = input;
        Debug.WriteLine("[AFTER] " + Context);

        // call my legacy code here
    }
}

The “MaDllAPart” is added as a reference to the WPF project : this let’s me create an instance of StartPoint without special configuration from my side. Be sure to use the full name (with the namespace) of the instanciated type.

private static void LaunchProcess()
{
    for (int i = 0; i < 10; i++)
    {
        var domain = AppDomain.CreateDomain("MonAppDomain_" + i);

        var startPoint = (MonPointDentree)domain
            .CreateInstanceAndUnwrap("MaDllAPart", "MaDllAPart.StartPoint");

        startPoint.Execute("module " + i);
    }
}

Happy coding !