简体   繁体   中英

ASP.NET C# external SDK not thread-safe

I have a Web API in ASP.NET/C#.

It uses an external 32-bit ActiveX SDK to communicate with a third-party application.

From my test, that SDK has problems when we connect two differents users at the same time. The second connection overwrites the first one.

If I call my API in two cURL loops, one connecting with userA and the other with userB, in some case, the call on userA will have the results of userB.

I don't have any static variables in my code, none that refer to the SDK for sure.

The only solution I can think of would be to "lock" the API while it is getting the response for the user. Is there any other solution ? If not, any pointer on how to do this in C# ?

The API has multiple controllers (think customer/invoice/payment/vendor), all of which are using the same SDK. Thus, a call to a method of CustomerController must lock calls to the other controllers too.

The lock only needs to be active while I using the SDK (which is probably 99% of the request time).

Edit 1:

The SDK is named "Interop.AcoSDK.dll", it is 32-bit. Visual Studio describe the file as "AcoSDK Library". It is an SDK for Acomba, an accounting program. The program itself has a very old structure, the origins dating back to the 80' in DOS (The program was named Fortune1000 back in those days). The interaction with the SDK is really not modern.

I've added the DLL to my project, and to use it, I call two parts.


            AcoSDKX AcoSDK = new AcoSDKX();
            int version = AcoSDK.VaVersionSDK;
            if (AcoSDK.Start(version) != 0)
            {
                throw new Exception("Failed to start SDK");
            }

            cie = new AcombaX();
            if (cie.CompanyExists(config.ciePath) == 0)
            {
                throw new Exception("Company not found");
            }

            int error = cie.OpenCompany(config.appPath, config.ciePath);
            if (error != 0)
            {
                throw new Exception("Failed to open company: " + cie.GetErrorMessage(error));
            }

            AcoSDK.User User = new AcoSDK.User
            {
                PKey_UsNumber = config.user
            };

            try
            {
                error = User.FindKey(1, false);
            }
            catch
            {
                throw new Exception("Failed to find user");
            }

            if (error != 0)
            {
                throw new Exception("Failed to find user");
            }

            error = cie.LogCurrentUser(User.Key_UsCardPos, config.pass);
            if (error != 0)
            {
                throw new Exception("Failed to login in Acomba: " + cie.GetErrorMessage(error));
            }

The cie attribute above is a private AcombaX cie in the class.

That class is called from my other class to handle the connection to the SDK.

My other class declare it as a standard object (non-static).

The config above refers to an object with attributes for the company/user the API request is for. Calls for multiple companies can be made.

In the moment, my problem is that calling for different companies, data ends-up being mixed up. So values from Company-B will show in my query of Company-A, for example, when I loop 100 calls to the API in cURL to both companies at the same time. It doesn't do it each time, just some time, for some queries. Probably when a call open the SDK for company-B while the call for company-A has already connected to the SDK but haven't started requesting data.

You need to share some more information about the ActiveX SDK (there is no such thing really). There are three types of ActiveX

( great explanation here )

ActiveX EXE: Unlike a stand-alone EXE file, an ActiveX EXE file is designed to work as an OLE server, which is nothing more than a program designed to share information with another program. It has an .EXE file extension.

ActiveX DLL: ActiveX DLL files are not meant to be used by themselves. Instead, these types of files contain subprograms designed to function as building blocks when creating a stand-alone program. It has a .DLL file extension.

ActiveX Control: Unlike an ActiveX DLL or ActiveX EXE file, an ActiveX Control file usually provides both subprograms and a user interface that you can reuse in other programs. It has an .OCX file extension.

Based on the format of the SDK and the way it's being used, there might be solutions to make the calls parallel.

Updating the question with some code, example etc, might enable me to shed some more light.

This could be starting multiple applications instead of one and using them as a pool, creating multiple objects from the same library and more.

I've posted a comment asking for clarification; I'm hoping that you're at a development stage where you can redesign this feature.

ASP.NET is, generally, really poor with non-trivial synchronous processes. It's easy to exhaust the thread pool, and concurrency issues like what you describe are not uncommon when moving from "desktop" or RPC architecture.

I would strongly suggest changing your WebAPI / ASP.NET architecture for these kinds of operations to a queue/task based approach. The client submits a task and then polls/subscribes for a completion result. This will allow you to design the backend to operate in any manner necessary to prevent data corruption problems due to shared libraries. Perhaps one long-lived backend process per Company which processes requests - I don't know enough about your needs to make intelligent suggestions, but you have a lot of options here.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM