1

I have ASP.NET Web Api project where I need to use VB6 Com dll. I have one controller, where I create object of class from com dll and use that object in my action. Everything seems to work when I call that action from ca. 2000-2500 threads, but when I run it from more threads, then I get this error while creating com object instance:

Creating an instance of the COM component with CLSID from the IClassFactory failed due to the following error: 800401f7 (or 800a01b8).

I found that com components run in STA Thread mode, but ASP.NET Web Api in MTA Thread mode, but I don't know if this caused the problem, because I couldn't find anything how to change mode to STA in ASP.NET Web Api project.

I use self hosted ASP.NET Web Api and I host it on Windows Service. When I stop the service and run it again, I can again send ca. 2500 threads.

EDIT: I created threads in sample windows application like this:

for (int i = 0; i < threadsCount; i++)
        {
            Task task = Task.Factory.StartNew(() => {
                for (int j = 0; j < loopCount; j++)
                {
                    SendRequest();
                }
            });
        }

EDIT2: Probably com object is not released, because in the Task Manager I can see that Handles grows up and I get this error when it has 2000+ handles. I call Marshal.ReleaseComObject, so I am not sure what can be wrong.

Bartosz Bialecki
  • 4,391
  • 10
  • 42
  • 64

1 Answers1

2

I wouldn't recommend changing your threading model of your ASP.NET Web Api project.

The STA mode, will add a synchronization layer between the call's to various components of the framework. (see Could you explain STA and MTA?)

As you 'add' this synchronization layer, you might experience deadlocks due to this synchronization.

I think it is better to cut down on the threads.

2500+ threads will not be efficient, try to consider a ThreadPool (http://msdn.microsoft.com/en-us/library/system.threading.threadpool%28v=vs.110%29.aspx)

You will gain performance as it will cut down the overhead of assigning/switching the Threads to a CPU.

As for the error: if you create 2500+ instances of the COM component, there might be some issues in memory allocation. Especially if it's a third party COM DLL, you cannot be sure that allocated memory is freed appropriate. Chances are big the COM component is not designed or tested for that amount of instances. Chances of memory leaks are big. etc. etc.

So my advise:

Stick with the MTA model, cut down on the threads.

Community
  • 1
  • 1
Stefan
  • 17,448
  • 11
  • 60
  • 79
  • I used so many threads only for testing, but this web api will running all the time as windows service, so the problem is also when I call the action e.g. 200 times with only 10 threads. Maybe there is any limit somewhere or something? Sorry but I'm new in c#. – Bartosz Bialecki Nov 25 '13 at 10:49
  • Where exactly do you create all these Threads? In the WebApi? In the windows service? Or are you posting 200+ request to the API? An other thing: as you are using COM, make sure to call `Marshall.ReleaseComObject` if you're done with the query-ed interface. See: http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.releasecomobject%28v=vs.110%29.aspx – Stefan Nov 25 '13 at 10:55
  • I make 200 request to the API from sample windows application. I create in my ApiController class the instance of com object, like _obj = new Class(); in constructor but I didn't call ReleaseComObject, so I will try this. – Bartosz Bialecki Nov 25 '13 at 11:02
  • I added ReleaseComObject to the destructor but it didn't help. – Bartosz Bialecki Nov 25 '13 at 11:15
  • Make sure to call `Marshal.ReleaseComObject` on every object you extract from the COM Component. For example, if your com component uses some: `YourComObject.GetSomeOtherObject()` method, make sure you `Marshal.ReleaseComObject` that object as well. Not all functions or `get` methodes will require a `Release`, it depents on the internal implementation of the `ReferenceCount`. If you release to often, there will be some errors (which are easily fixed). If you don't release enough, you'll experience hard-to-debug-memory-leaks and all sort of issues. – Stefan Nov 25 '13 at 11:16
  • I only create that one object in constructor and in action call it one function of that object and in destructor I release that object. – Bartosz Bialecki Nov 25 '13 at 11:31
  • `"I added ReleaseComObject to the destructor but it didn't help."` do it immediate after the moment you're done with the COM object. `.NET` uses a garbage collector. It is undetermined when your objects will hit the destructor. It might not resolve your issue, but if you don't it will cause other problems. As for the threading; I don't think the WinAPI is actually handling 200+ requests simultaneously. You can try to send the requests in batches of 10, if the error occurs after +/-25 times, the problem must be in the memory management (Releases) of the COM component. – Stefan Nov 25 '13 at 11:46
  • I edited my question, so you can see how I make requests to the api. WHhen I set threadCount to 25 and loopCount everything is ok, problem starts when e.g. threadCount = 250 and loopCount = 10. I create now com object in the action and release it immediately. – Bartosz Bialecki Nov 25 '13 at 12:18
  • How to hell is possible to use 2500 threads??? isn't it a 2.5gb of memory? and why so many?? Can I see an example of how you do it"? – hackp0int Nov 25 '13 at 12:20
  • @IamStalker you can see it in my edited question. I want to test multiple simultaneously request to the api. – Bartosz Bialecki Nov 25 '13 at 13:04