ServiceStack +第三方COM Inteop + Context断开异常

时间:2013-05-10 18:30:57

标签: multithreading servicestack com-interop unmanaged managed

我在测试ServiceStack服务时遇到了Context Disconnected错误。我假设这是由于GC对象的响应回调线程,我的ServiceStack服务的对象和COM服务器自己的垃圾收集之间的竞争条件失败。

编辑:这很可能是这里解释的同一问题:Avoiding disconnected context warning when shutting down a thread on which STA COM objects have been created - 它建议我实现“一些引用计数以保持工作线程活着,直到它的所有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();
    }
}

1 个答案:

答案 0 :(得分:1)

有关Concurrency Model中并发模型的更多信息,请参阅Servicestack wiki。

基本上在ASP.NET中,ServiceStack没有显式创建新线程,即请求由同一个IIS / ASP.NET HTTP Worker线程处理。

在自托管的HttpListener主机中,默认的AppHostHttpListenerBase也在它在线程池线程上执行的AppHostHttpListenerLongRunningBase App Host中使用相同的IO回调线程。这是最近发布的researching the the optimal thread strategy个不同的自托管HttpListener主机实现。