How are STA COM components handled when used in a WCF service hosted in IIS (7+)? - wcf

From what I understand, when a COM component marked as using STA is used from an MTA thread, the calls are supposed to be marshalled to an STA thread and executed from that dedicated thread. In the case of a Windows client application, this would mean that it would execute on the UI thread (if marked as STA), and that callbacks from the COM component to me would be handled by Windows messages sent to a hidden window and processed on the Windows message loop.
What happens though if I use a STA COM component in a WCF service hosted in IIS? Will the worker process have a Windows message loop on a STA thread? Can I fire up my own STA thread with its own message loop?

The COM runtime looks after the dispatching of calls to methods on a COM object inside an STA: you are right that this is based on the same OS mechanism used for dispatching Windows messages, but you don't need to worry about making this happen - COM does this for you under the hood.
What you do need to worry about is which STA your COM objects are going to live in. If you instantiate apartment-threaded COM objects using COM Interop from a WCF service, you need to be careful.
If the thread on which you do this is not an STA thread, then all in-process COM objects will live in the default Host STA for the IIS worker process. You do not want this to happen: all your COM objects for all service operations will end up in this same STA. The clue is in the name - there is just one thread for all the objects - and all calls to their methods will be serialized waiting for the one and only thread in the apartment to execute them. Your service will not scale to handle multiple concurrent clients.
You need to make sure that COM objects you instantiate to service a particular WCF request are in their own STA separate from objects created for other requests. There are broadly two ways to do this:
Spin up your own Thread, specifying ApartmentState.STA in SetApartmentState() before you start it, on which to instantiate the COM objects for a particular request. This is the approach detailed by Scott Seely in the link in Kev's answer: he ensures that each service operation call is invoked on a new STA-initialised Thread. A harder but more scalable solution along these lines would be to implement a pool of reusable STA-initialised Threads.
Host your COM objects in a COM+ Application, so that they live in a separate DllHost process, where COM+ (through its abstraction called the Activity) can take care of putting the objects for different requests into different STAs.
I'm not sure exactly what you mean when you refer to callbacks. Perhaps you mean COM method calls on some COM interface implemented in your managed code, via a reference passed in to the COM objects as an argument to one of the COM objects' methods: if so, this should just work. But perhaps you mean something else, in which case perhaps you could amend the question to clarify.

I've found that you need to pump messages on your STA thread in a WCF service or you miss callbacks from the COM object.
The following code works, but it requires you call the COM object via a Dispatcher.
ComWrapper comWrapper;
Thread localThread;
Dispatcher localThreadDispatcher;
public Constructor()
{
localThread = new Thread(ThreadProc)
{
Name = "test"
};
localThread.SetApartmentState(ApartmentState.STA);
AutoResetEvent init = new AutoResetEvent(false);
localThread.Start(init);
init.WaitOne();
}
private void ThreadProc(object o)
{
localThreadDispatcher = Dispatcher.CurrentDispatcher;
((AutoResetEvent)o).Set();
comWrapper = new ComWrapper()
Dispatcher.Run();
localThreadFinished.Set();
}
And then make calls as follows.
public void UsefulComOperation()
{
localThreadDispatcher.Invoke(new Action( () => comWrapper.UsefulOperation);
}

Related

Re-issuing COM call on the UI thread

I am trying to decipher the paragraph below, taken from a blog post here which describes COM history in the context of the development for the Visual Studio IDE:
When everything was C++ native code, COM ensured that almost
everything happened on the main STA thread (i.e. the UI thread). If
code running in another apartment (e.g. a background thread) called
any of these COM components the background thread would block while
the call was re-issued on the main thread. This protected the COM
component from having to deal with concurrent execution, but left it
open to reentrancy (being invoked while in an outbound call). This
technique worked whether the caller was managed (automatically) or
native code (via the proxy stub that COM would generate for the
caller).
The questions I have:
What is the mechanism by which a call is re-issued on another thread? Can you give an example?
Is the problem mentioned as ‘concurrent execution’ the same as that of thread safety?
What is being invoked while on an outbound call?
Thank you.

ElasticClient Dispose

I'm new to this. I'm working with ElasticClient (.Net) and I was curious if:
Is it thread safe? I assume so because it uses pooling.
Should I do anything to clean up the client resources when I'm done? It does not implement IDisposable.
Thanks!
Bob
On thread safety: https://github.com/elastic/elasticsearch-net/issues/23
The ElasticClient holds a single IConnection responsible for doing
async and sync http calls. The IConnection does not reuse
httprequests and uses thread local state for data thats being passed
around during the stages of the request. It should thus be thread
safe.
On disposing: https://github.com/elastic/elasticsearch-net/issues/101
ElasticClient is almost stateless except for a static CLR type info
cache that is threadsafe so you can even use one client over threads.
Disposing is also handled by Nest and ElasticClient only exposes
POCO's.

Best practice for calling an STA Visual Basic 6.0 COM object in a WCF service: Concurrent access

I have a WCF service which calls an STA Visual Basic 6.0 COM object. Everything works normally if only one client is using the service, but as soon as concurrent users start to call it, I'm in trouble and getting all kinds of random errors when calling one of the methods of the COM object.
At first I fixed this problem by adding support for the STAOperationBehavior attribute with the help of the article Calling an STA COM Object from a WCF Operation.
Well, it helped a lot and for some time everything seemed to work well, but now I started to get System.AccessViolationException errors on a particular server when more than one user is calling the service.
I've read that this is probably a thread problem, and I should use mutex or instancecontext in my web service.
What is the best practice for making sure that concurrent users can use an STA COM object in a WCF service without any problems?
If the object is not designed to be used simultaneously by multiple users, then you simply cannot allow multiple users to use it.

Not disposing of a WCF proxy?

I have a WCF service which is a singleton and which manages a collection of proxies to another WCF service which is session-based. The singleton creates a new proxy and passes it some work to do, and the session-based service makes calls back to the singleton service when certain activities complete (pretty much all of the OperationContract methods are one-way). The typical completion path is that the singleton receives an event from a hardware device when the process is complete, and it calls a method on the session-based service which returns the final status, and then disposes of its proxy. When an error situation is encountered and the session-based service can't continue with what it needs to do, I need to make a call back to the singleton to let it know to dispose of the proxy associated with that instance. However, to make the WCF method call back to the singleton, I need to create a proxy back to the singleton. What I'm seeing happen is that the singleton disposes of its proxy as expected, but every time the proxy to the singleton that the session-based service created times out when I try to dispose of it. Since the session ends with that method call and the instance will be disposed of, does it matter if the proxy it created doesn't get properly disposed?
Disposing of a WCF service is not the same as disposing of any other object that implements IDisposable. It is ok to dispose of the service when it is in a good state but when a fault occurs the dispose method will throw another exception.
Some insight is here and perhaps use the WCFProxyGenerator but I have not tried it
Not sure exactly the problem with the session based service and whether it is different from the WCF service.
My recommendation is not to use a singleton but use Dependency Injection to give the class that uses the WCF service a factory so when it wants the service it can create it. And when a fault occurs it can throw away the old and create a new one. Without seeing some code it is hard to see if this is possible.

How to ensure that the same thread is used to execute code in IIS?

We have a third party dll that is used in our web service hosted in IIS6. The problem is that once this dll is loaded into memory, the exception AccessViolationException gets thrown if a thread different then the one that created it tries to execute any code within the dll. The worker process is multi threaded and each call to the web service will get a random thread from the pool. We tried to unload it from memory and reload it each time we needed it, but I guess only the front end is .Net and the rest is unmanaged so it never actually gets completely unloaded from memory. We are using VB and .Net 2.0. Any suggestions?
(Response to Rob Walker)
We thought about creating a new thread and using it to call the dll, but how do we make the thread sit and wait for calls? How do you delegate the call to the thread without having the Dispatcher class supplied by .Net 3.0? Creating a hidden form and putting it in a message loop might work. And then we could call the Invoke() method of the form. But I can see many problems occurring if we create a form inside an IIS hosted web service.
I have read about a class in .net 3.0 called Dispatcher that allows you to put a thread in a loop and then call the method Invoke() using a delegate to execute a method using the thread. But this solution will not work if you cannot update to .Net 3.0. Another solution would be to host the third party dll in another application on the server and use some form of Remoting to access it. But you may still have a problem with the Remoting because it behaves similar to IIS and will also pick a random thread to execute the code . To get around this, you could put a wrapper around the dll and use it to delegate the calls to the UI thread by using the Invoke() method of the form.
I think you need to look at using a wrapper thread that handles all calls to the DLL, and deals with the serialization.
This thread is outside of the managed thread pool, so you control its lifetime. But even this would not be foolproof unless you can prevent IIS from restarting the app domain your web service is in.
You also need to worry about what happens when two web service requests come in at the same time. Is each call into the DLL standalone, or do you have to group together all the calls associated with a single web service request before allowing any other request to be serviced?
You could create a service that hosts the extra DLL. Via remoting you access the service, this will dispatch the calls the the thread that manages the DLL.
This way you have control over the thread that calls the DLL, and over the lifetime of the thread.
I'm a bit rusty, but you might try wrapping calls to the DLL in a single threaded apartment COM object. This would ensure that all calls go through the COM object's windows messaging thread. I think you would have to register the component in a server application within Component Services to do this.
Can you run the dll inside different threads as different instances? Like thread1 creates an instance of this third party dll, and thread2 also does, but as long as thread1 doesn't try to use thread2's instance it won't throw that exception? If thats the case, .Net never unloads any code once its loaded, if you load an assembly and then remove it, it still sits in that application pool. If you can create more than one instance at a time, you could load it up in a separate app pool you control per a request, then unload the app pool. Performance might drop though.