Lock Web API controller method

后端 未结 2 871
孤独总比滥情好
孤独总比滥情好 2021-02-13 10:38

I\'m developing an ASP.NET Web Api application with C# and .Net Framework 4.7.

I have a method in a controller that I want to execute only by one thread at a time. In ot

2条回答
  •  野趣味
    野趣味 (楼主)
    2021-02-13 11:17

    Your lock solution should work fine. If the request fails, then the lock will be released, and other pending requests can then enter the lock. A deadlock wont occur.

    The only issue with this solution, is web requests will go on hanging for possibly long periods of time (Which may result in time outs from the client end).

    public class MyApi : ApiController
    {
        public static readonly object LockObject = new object();
    
        [HttpPut]
        [Route("api/Public/SendCommissioning/{serial}/{withChildren}")]
        public HttpResponseMessage SendCommissioning(string serial, bool withChildren)
        {
            lock ( LockObject )
            {
                //Do stuff
            }
        }
    }
    

    To solve the issue with hanging requests, you should utilize a queue, and poll the back end (Or if you're fancy, try SignalR) until your job is complete. For example:

    //This is a sample with Request/Result classes (Simply implement as you see fit)
    public static class MyBackgroundWorker
    {
        private static ConcurrentQueue> _queue = new ConcurrentQueue>()
        public static ConcurrentDictionary Results = new ConcurrentDictionary();
    
        static MyBackgroundWorker()
        {
             var thread = new Thread(ProcessQueue);
             thread.Start();
        }
    
        private static void ProcessQueue()
        {
             KeyValuePair req;
             while(_queue.TryDequeue(out req))
             {
                 //Do processing here (Make sure to do it in a try/catch block)
                 Results.TryAdd(req.Key, result);
             }
        }
    
        public static Guid AddItem(Request req)
        {
            var guid = new Guid();
            _queue.Enqueue(new KeyValuePair(guid, req));
            return guid;
        }
    }
    
    
    public class MyApi : ApiController
    {
        [HttpPut]
        [Route("api/Public/SendCommissioning/{serial}/{withChildren}")]
        public HttpResponseMessage SendCommissioning(string serial, bool withChildren)
        {
            var guid = MyBackgroundWorker.AddItem(new Request(serial, withChildren));
            return guid;
        }
    
        [HttpGet]
        [Route("api/Public/GetCommissioning/{guid}")]
        public HttpResponseMessage GetCommissioning(string guid)
        {
            if ( MyBackgroundWorker.Results.TryRemove(new Guid(guid), out Result res) )
            {
                return res;
            }
            else
            {
                //Return result not done
            }
        }
    }
    

提交回复
热议问题