AppDomainをスレッドごとに分ける

PC上で使うことだけを想定されて作成された、static変数にデータを入れるようなライブラリをWebサービスで使わなければならない。簡単に言うとこんなライブラリ。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyLib
{
    public class MyClass
    {
        private static string _message;

        public string Message
        {
            get { return _message; }
            set { _message = value; }
        }

        public string greeting(string name)
        {
            return _message + ", " + name;
        }
    }
}

これをマルチスレッド環境で正しく動作させるため、スレッドごとにAppDomainを分けてみる。

using System;
using System.ComponentModel;
using System.Reflection;
using System.Threading;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;

using MyLib;

namespace MyService
{
    // Webサービスメソッド
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [ToolboxItem(false)]
    public class MyService : WebService
    {
        [WebMethod]
        public string MyMethod(string message, string name)
        {
            // このインスタンスとそのクラスは、全てスレッドローカル
            // static変数もスレッドごとに異なる
            MyClass instance = ThreadLocalMyClass.Instance;

            // class を使った処理…
            clazz.Message = message; 
            return instance.greeting(name);
        }
    }

    internal class ThreadLocalMyClass
    {
        [ThreadStatic]
        private static AppDomain _domain;

        [ThreadStatic]
        private static MyClass _instance;

        private static AppDomain Domain
        {
            get
            {
                if (_domain == null)
                {
                    _domain = AppDomain.CreateDomain(
                        String.Format("AppDomain{0}", Thread.CurrentThread.GetHashCode()),
                        null,
                        AppDomain.CurrentDomain.SetupInformation);
                }
                return _domain;
            }
        }

        public static MyClass Instance
        {
            get
            {
                if (_instance == null)
                {
                    // 引数はnamespace、クラス完全修飾名
                    _instance = (MyClass)Domain.CreateInstanceAndUnwrap(
                        "MyLib", "MyLib.MyClass");
                }
                return _instance;
            }
        }
    }
}

こんな感じで良いのかねぇ。

ThreadStaticって楽ですね。