1

在测试我的 ServiceStack 服务时,我遇到了上下文断开错误。我认为这是由于 COM 对象的响应回调线程、我的 ServiceStack 服务对象和 COM 服务器自己的垃圾收集之间的竞争条件失败。

编辑:这很可能与此处解释的相同问题:在关闭已创建 STA COM 对象的线程时避免断开连接的上下文警告- 建议我实施“一些引用计数以保持工作线程处于活动状态,直到它的所有 COM 对象肯定已经发布” (选项 #1 - 重新编写 COM 对象以支持 MTA 线程模型是不可能的,因为 COM 对象来自第 3 方库。)

编辑(2):明智地使用Marshal.ReleaseComObject(obj)内部回调方法消除了问题。幸运的是,所讨论的 COM 对象可以清楚地识别,并且数量有限。

1.如何防止发生Disconnected Context异常?
2. 关于线程和生命周期,ServiceStack 服务对象的生命周期是什么?

下面的测试通过了。但是,如果请求需要很长时间才能返回(对于 'long time' > 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,将其传递给第 3 方服务的请求对象,并调用 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中的并发模型的更多信息,请参阅并发模型wiki 。

本质上,在 ASP.NET 中,ServiceStack 不会显式创建新线程,即请求由相同的 IIS/ASP.NET HTTP Worker 线程处理。

在自托管的 HttpListener 主机中,默认的 AppHostHttpListenerBase 也使用相同的 IO 回调线程,在 AppHostHttpListenerLongRunningBase 应用主机中,它在线程池线程上执行。这是最近的一篇文章,研究了不同自托管 HttpListener 主机实现的最佳线程策略。

于 2013-05-10T19:18:54.077 回答