3

I am in need of some guidance on a project I am working on. We are looking for a replacement for CORBA server setup. In a nutshell we currently run a CORBA deamon service that hosts 10 instances of a C++ exe that is the entry point into our calculation process. The C++ code hooks into a bunch of different .net and C++ dlls and OCXs via COM. We also have another version of the executable that is compiled as a .dll that we are able to call in a similar fashion but it is only a single instance system so all is well there.

We are now looking to replace the CORBA components with a WebAPI so I have put together a basic ASP.net webAPI project that is able to process the requests into this C++ dll. Again, this works great when it only needs to handle 1 request at a time. Things start going sideways when I start testing concurrent requests. The request come into my handler just fine and I can see the 5 requests (I have logging everywhere tracking whats going on,) and each thread creates an instance of the dll but they are run synchronously.

What I have figured out is that even though there are multiple threads going in the ASP.net handler, the dll is STAThreaded (this is confirmed in the code) so the calls are queued up and only processed 1 at a time. My guess here is because the threads are all inside the same process the dll treats all the threads as the same apartment (STAThread) and causes the queue.

I have tried different async/await and task.run code and I can see different threads but it still comes down to the same process which makes the dll run synchronously. I did try change the dll to be MTA by changing the CoInitializeEx(NULL,0x2) to CoInitializeEx(NULL,0x0) but that didn't seem to change anything.

I am now running out of ideas and I don't think changing to use the .exe version and spawning multiple process is going to work because there is the CORBA stuff that allows a return object to be created and communicated back to the calling code. I need to be able to get the objects that are created in the exe to send back in the request.

Sorry for the long post, hopefully someone will take the time to read this wall of text and have some ideas of what I can try.

Thank you!

DennisC
  • 133
  • 1
  • 4
  • 2
    Lots of confusion here. A .DLL is not "stathreaded". A given thread is either STA or MTA. This choice is made by the developer who creates the thread (using CoInitializeXX), not by anyone else. Objects are marked as being Single, Apartment, Both, Free, etc. and that just explicits how they behave in a given apartment (~thread). In a web server, everything is complicated by the fact in general you down own the threads (they are in a pool, etc.). Hmmm... your all setup and architecture sounds complex (C#, C++, CORBA, COM, .NET, Threads, Web) and difficult to help/fix with a question in SO... – Simon Mourier Nov 21 '19 at 19:00
  • There is A LOT going on in our system and the core components have been around for 20 years. As for the dll not being STATHreaded, this is the constructor: CComInit() { CoInitializeEx(NULL,0x2); } Doesn't this force the dll to be STAThreaded? I know in other .Net apps I have written that uses this dll I need to use [STAThread] decorator on my Main() to keep things working properly. – DennisC Nov 21 '19 at 19:15
  • Reading your question, I've not doubt there's a lot going on - I've been myself in the COM vicinity for 25 years :-), that's what I meant by the fact it's probably too much for a question on SO. Anyway, calling CoInitialize in a DLL is the typical sign of a mistake on how Windows, COM and threads work (I'm not saying it won't work, as you say you have it working today). STAThread just means the thread starting your program will call CoInitialize itself. – Simon Mourier Nov 21 '19 at 19:34

2 Answers2

0

I would suggest that the WebAPI architecture is a poor solution to your problem. Typically you do not want to spawn long-running or blocking processes from ASP.NET, because it's quite easy to exhaust the threadpool and prevent the server from being able to handle new requests.

If you do want to continue having a WebAPI endpoint, I would start with taking the requests and putting them in a queue, and having the client poll or subscribe for the completed result.

You may be interested in looking a what they're doing with gRPC in dotnetcore 3.0 - if you want to keep that kind of architecture, but update the platform.

brnlmrry
  • 399
  • 2
  • 7
  • I have been looking at gRPC but we are a legacy system built on a C/C++ calculation engine that is not going to be rewritten any time soon. I am waiting for .Net core to implement the COM interopt stuff that is currently missing and then it might become a solution for us. It does sound like its coming in a relatively soon update to .Net Core 3 – DennisC Nov 21 '19 at 19:11
-1

You can create multiple app domains. App domain is "It can be considered as a Lightweight process which is both a container and boundary" ref. Load your DLLs into that different domains. This way every app domain you create will load your COM DLLs separately. Create proxies using MarshalByRefObject as used here. Write an orchestrator that distributes requests to app domains and get the results from appdomains and send responses. Keeps tracks of which domain is busy which is not or create new domains for the request.

Also different methods mentioned in this link

Eldar
  • 9,781
  • 2
  • 10
  • 35
  • I don't know that multiple app domains are the right way to go either, but I have been looking into multiple worker processes, ie Web Garden in IIS, but while there are multiple processes now running it seems to still just be using 1 of them. I write the process ID in to the logs when running and they all have just 1 of the 5 running process ids. – DennisC Nov 21 '19 at 19:55