Question

I'm getting Context Disconnected errors when testing my ServiceStack service. I assume it's due to failing race conditions between the GC for the COM object's response callback thread, my ServiceStack Service's objects, and the COM server's own garbage collection.

Edit: It's most likely the same problem explained here: Avoiding disconnected context warning when shutting down a thread on which STA COM objects have been created -- which recommends I implement "some reference counting to keep the worker thread alive until all of it's COM objects have definitely been released" (option #1 - re-write the COM objects to support the MTA threading model is not possible, given that the COM objects are from a 3rd party library.)

Edit (2): Judicious use of Marshal.ReleaseComObject(obj) within the callback method eliminated the problem. It was fortunate that the COM objects in question were clearly identifiable, and in in limited number.

1. How can I prevent Disconnected Context exceptions from occurring?
2. What is the lifecycle of a ServiceStack service object, with regard to threads and lifetime?

The test below passes. However, if the request takes a long time to return (for values of 'long time' > 30 seconds), I get a disconnected context error after the test completes, half the time.


    [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);
    }

My ServiceStack service passes a request class instance to the COM server. The class implements a callback method to process the response. My ServiceStack service creates an AutoResetEvent, passes it into the 3rd party service's request object, and calls WaitOne() to wait for the response data. The callback method is executed, asynchronously, in a new thread and calls Set() to notify the ServiceStack service that the data has been processed. (Error handling is similar - code omitted for clarity.) Here are the simplified ServiceStack service and the COM Object's DataClient class, with required callback method.

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;
    }
}

And the COM object's request class, illustrating the callback.

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();
    }
}
Was it helpful?

Solution

Please see the Concurrency Model wiki for more info about the concurrency model in Servicestack.

Essentially in an ASP.NET no new threads are explicitly created by ServiceStack, i.e. the Request is handled by the same IIS/ASP.NET HTTP Worker thread.

In a self-hosted HttpListener host, the default AppHostHttpListenerBase also uses the same IO callback thread, in a AppHostHttpListenerLongRunningBase App Host it executes on a Thread Pool thread. Here's a recent post researching the the optimal thread strategy of different self-hosted HttpListener host implementations.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top