1

ServiceStack サービスをテストするときに Context Disconnected エラーが発生します。COM オブジェクトの応答コールバック スレッド、ServiceStack サービスのオブジェクト、および COM サーバー自体のガベージ コレクションの GC 間の競合状態が失敗したためだと思います。

編集:ここで説明されているのと同じ問題である可能性が最も高い: STA COM オブジェクトが作成されたスレッドをシャットダウンするときに切断されたコンテキストの警告を回避する- これは、「すべての COM オブジェクトになるまで、ワーカー スレッドを存続させるためにいくつかの参照カウントを実装することをお勧めします」確実にリリースされています」(オプション #1 - COM オブジェクトがサード パーティのライブラリからのものであるため、MTA スレッド モデルをサポートするように COM オブジェクトを書き直すことはできません。)

編集(2):コールバックメソッド内での賢明な使用Marshal.ReleaseComObject(obj)により、問題が解消されました。問題の COM オブジェクトが明確に識別でき、しかも数が限られていたことは幸運でした。

1. 切断されたコンテキストの例外が発生しないようにするにはどうすればよいですか?
2. スレッドとライフタイムに関して、ServiceStack サービス オブジェクトのライフサイクルはどのようなものですか?

以下のテストはパスします。ただし、リクエストが返されるまでに長い時間がかかる場合 (「長い時間」の値が 30 秒を超える場合)、テストの完了後に切断されたコンテキスト エラーが半分の時間発生します。


    [TestFixtureSetUp]
    public void OnTestFixtureSetUp()
    {
        // TODO: remove default login credentials from code
        // Instantiate singleton wrapper to COM object
        var appSettings = new AppSettings();
        var config = appSettings.Get("3rdPartyLogin", new Config { UserName = "debug_username", Password = "debug_password" });
        COMServer.SetUser(config.UserName,config.Password);

        appHost.Init();
        appHost.Start(ListeningOn);
    }

    [TestFixtureTearDown]
    public void OnTestFixtureTearDown()
    {
        appHost.Dispose();
    }

    [Test]
    public void TestDataList()
    {
        JsonServiceClient client = new JsonServiceClient(BaseUri);
        client.ReadWriteTimeout = new TimeSpan(0, 10, 0); // 5 minutes to timeout
        DataList response = client.Get(new DataList());
        Assert.Contains("Expected Item", response.data);
    }

私の ServiceStack サービスは、要求クラスのインスタンスを COM サーバーに渡します。このクラスは、応答を処理するためのコールバック メソッドを実装します。私の ServiceStack サービスは AutoResetEvent を作成し、それをサードパーティ サービスの要求オブジェクトに渡し、WaitOne() を呼び出して応答データを待ちます。コールバック メソッドは新しいスレッドで非同期に実行され、Set() を呼び出して、データが処理されたことを ServiceStack サービスに通知します。 (エラー処理も同様です - わかりやすくするためにコードは省略されています。) 以下は、単純化された ServiceStack サービスと、必要なコールバック メソッドを備えた COM オブジェクトの DataClient クラスです。

public class DataListService : Service
{
    public DataList Get(DataList request)
    {
        ComDataClient c = new ComDataClient();
        try
        {
            ComDataService data = COMServer.getDataService();
            if (data != null)
            {
                AutoResetEvent requestEvent = new AutoResetEvent(false);
                c.requestEvent = requestEvent;
                data.setClient(c);

                data.getData(ComObjClass.enumDataId);
                requestEvent.WaitOne();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error Connecting to Data Service: " + ex.Message);
        }
        return c.responseData;
    }
}

そして、コールバックを示す COM オブジェクトの要求クラス。

class ComDataClient : IDataClient
{
    public DataList responseData { get; set; }
    public AutoResetEvent requestEvent { get; set; }

    public void acceptData(ref KeyValue[] names, ComObjClass.Content enumDataId)
    {
        responseData = new DataList();
        responseData.data = new List<String>();

        foreach (KeyValue name in names)
        {
            responseData.data.Add(name.key_);
        }

        // Signal the application thread
        requestEvent.Set();
    }
}
4

1 に答える 1

1

Servicestackの同時実行モデルの詳細については、 Concurrency Model wiki を参照してください。

基本的に、ASP.NET では、新しいスレッドが ServiceStack によって明示的に作成されることはありません。つまり、要求は同じ IIS/ASP.NET HTTP ワーカー スレッドによって処理されます。

セルフホステッド HttpListener ホストでは、デフォルトの AppHostHttpListenerBase も同じ IO コールバック スレッドを使用し、AppHostHttpListenerLongRunningBase アプリ ホストではスレッド プール スレッドで実行されます。これは、さまざまな自己ホスト型 HttpListener ホスト実装の最適なスレッド戦略を調査している最近の投稿です。

于 2013-05-10T19:18:54.077 に答える