Locking an ASP.NET application variable

10,098

Solution 1

If it is vital you should only have a single call to the service at any time I recommend you write your own Windows Service. This depends on how much fault tolerance you want.

Let's say for example you make a call to the web service, but then the application pool is recycled. When a new request comes in it would be handled by a new instance of your application which could then make the call to the web service (Even if the other instance is running).

You could pass this off to a windows a service, then use a polling mechanism from the client to check if the service has finished (Client would ask IIS are you done, IIS would look for some indication from windows service that it was done). This approach will avoid locking anything in IIS, and you won't waste critical resources such as threads in your thread pool waiting on a third party service.

You should never lock on a single resource in your web application...it's just too risky.

Edit

Another option is to use the Monitor object directly:

    if (System.Threading.Monitor.TryEnter(syncObj,10))
    {

        try
        {
            //CallWebService
        }
        finally
        {
            System.Threading.Monitor.Exit(syncObj);
        }
    }
    else
    {
        //Tell Client they are still waiting

    }

TryEnter will block until a lock is made or 10 milliseconds has passed. You could then in your timeout tell the client they need to retry. You could then have your client code decide if it should reissue the request. You could also use a semaphore or mutex (forget which one is more appropiate here). But it would assuming you have permissions to use them, give you something you can lock on at the machine level which would prevent the app recycling use case.

Solution 2

You should create a private static readonly object _lock = new object(); in the class that makes the webservice calls, and use that as a lock. Since the object is static there will only be one of them throughout all of your application, a Singleton object if you wish (http://en.wikipedia.org/wiki/Singleton_pattern)

public class MyWebServiceWrapper
{
   private static readonly object _lock = new object();

   public void CallWebService()
   {
      lock(_lock)
      {
         var objWebService = (ThirdPartWebService)Application["ThirdPartWebService"];
         objWebService.CallThatNeedsToBeSynchronized();
      }
   }
}

If your class that makes the WebService call doesn't do anything else, you can also just make a lock on this (lock(this)). Just remember, that this will mean, that if you have several methods, the call to one method will block all the other methods as well, which is why you normally shouldn't lock this.

Solution 3

You can lock on a static shared object. This is a common way to use lock´s in .Net. By using a static object you know it will be shared among all threads, and the lock is ensured.

As for making the app unstable if the call fails, that has to be due to the call not disposing properly. By using the "using" statement you are ensuring that dispose is called at the end of the call. Read this SO thread on why/why not you should dispose a web service regarding performance.

static readonly object _lockObj = new object();
...
lock( _lockObj )
{ 
   ThirdPartWebService objWebService = Application["ThirdPartWebService"] As ThirdPartWebService;
   objWebService.CallThatNeedsToBeSynchronized();
}
Share:
10,098
andHapp
Author by

andHapp

Software programmer living in Vermont.

Updated on June 04, 2022

Comments

  • andHapp
    andHapp almost 2 years

    I'm using a 3rd party web service in my ASP.NET application. Calls to the 3rd party web service have to be synchronized, but ASP.NET is obviously multi-threaded and multiple page requests could be made that result in simultaneous calls to the 3rd party web service. Calls to the web service are encapsulated in a custom object. My thought is to store the object in an application variable and use the C# lock keyword to force synchronized use of it.

    I'm nervous, because I'm new to multi threaded concepts and I've read that you shouldn't lock a public object (which my application variable effectively is). I've also read that if the locked block of code fails (which it could if the web service fails), then it could destabilize the app domain and bring down the application.

    I should mention that the 3rd party web service is rarely used in my website and it's going to be rare that 2 requests to it are made at the same time.

    Here's a rough code sample of how I'd make calls to the web service:

    ThirdPartWebService objWebService = Application["ThirdPartWebService"] As ThirdPartWebService;
    lock (objWebService)
    {
      objWebService.CallThatNeedsToBeSynchronized();
    }