2017-07-24 46 views
0

我有一個ASP.NET網絡應用程序,它有一個IHttpHandler來處理POST請求(基本上,它將處理JSON,然後將處理結果發送回客戶端)。如何在ASP.NET Web應用程序中的IHttpHandler上實現隊列?

我想在我的應用程序中實現一個隊列系統,這樣如果有模擬的post請求,它們不會並行處理,而是一個接一個地處理。

問題

  1. 什麼是最好的方式實現的?
  2. 在應用程序中,我應該聲明Queue對象?
  3. 每次向隊列添加項目 時,如何附加特定功能(將執行處理的功能)?

我無法在Page_Load()事件中聲明隊列,因爲當網頁打開時不會發送請求。我需要隊列始終等待傳入的POST請求。如果我在IHttpHandler中聲明隊列,每當POST請求到來時,隊列就會重置。

謝謝!

回答

0

實現此目的的一種方法是改爲使用IHttpAsyncHandler和單例服務類。工作線程等待添加到ConcurrentQueue的BlockingCollection的新項目。這將啓用傳入請求的串行處理。需要在處理第一個請求之前啓動服務類中的工作線程,可以從全局Application_Start例程或通過向AssembleInfo.cs文件添加PreApplicationStartMethod來調用啓動方法。

using System; 
using System.Collections.Concurrent; 
using System.Threading; 
using System.Web; 

namespace webgateway 
{ 
    public class RequestHandler : IHttpAsyncHandler, IDisposable 
    { 


     public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) 
     { 

      RequestContext requestContext = new RequestContext(cb, context, extraData); 

      Service.Instance.QueueRequest(requestContext); 

      return requestContext; 

     } 


     //Start could be called from the Global asax or by adding this attribute to the Assembly.cs 
     //[assembly: PreApplicationStartMethod(typeof(webgateway.RequestHandler), "Start")] 
     public static void Start() 
     { 

      Service.Instance.Start(); 
     } 

     public void EndProcessRequest(IAsyncResult result) { 
     } 
     public bool IsReusable { get { return true; } } 
     public void ProcessRequest(HttpContext context) { } 
     public void Dispose() { } 
    } 

} 


public sealed class Service 
{ 

    private static readonly Service _Instance = new Service(); 
    public static Service Instance 
    { 
     get { return _Instance; } 
    } 
    private Service() 
    { 
    } 


    private static bool _running = false; 

    private BlockingCollection<RequestContext> blockingQueue = new BlockingCollection<RequestContext>(new ConcurrentQueue<RequestContext>()); 


    public void Start() 
    { 
     _running = true; 
     ThreadPool.QueueUserWorkItem(worker, null); 

    } 

    private void worker(object state) 
    { 

     RequestContext requestContext; 

     while (_running) 
     { 

      //Block until a new item is added to the queue 
      if (blockingQueue.TryTake(out requestContext, 10000)) 
      { 

       //You could delegate the work to another function , class , library or process inline here... 

       //Simulate a random delay 
       Thread.Sleep((new Random()).Next(1000, 5000)); 


       //Make sure the client is connected before sending the response 
       if (requestContext.HttpContext.Response.IsClientConnected) 
       { 
        requestContext.HttpContext.Response.BufferOutput = false; 
        requestContext.HttpContext.Response.ContentType = "text/plain"; 
        requestContext.HttpContext.Response.Write(requestContext.HttpContext.Request["echo"]); 
        requestContext.HttpContext.Response.Flush(); 
        requestContext.CompleteCall(); 
       } 

      } 

     } 

    } 

    public void Stop() 
    { 
     _running = false; 
    } 

    public void QueueRequest(RequestContext requestContext) 
    { 

     if (!blockingQueue.TryAdd(requestContext)) 
     { 
      //handle error 
     } 
    } 

} 

public class RequestContext : IAsyncResult 
{ 

    private ManualResetEvent _event; 
    private object _lock = new Object(); 
    private AsyncCallback _callback; 
    private HttpContext _httpContext; 
    private bool _completed; 
    private bool _completedSynchronously; 
    private object _state; 

    public RequestContext(AsyncCallback cb, HttpContext hc, object state) 
    { 
     _callback = cb; 
     _httpContext = hc; 
     _completedSynchronously = false; 
     _completed = false; 
     _state = state; 
    } 

    public HttpContext HttpContext 
    { 
     get { return _httpContext; } 
    } 

    public void CompleteCall() 
    { 
     lock (_lock) 
     { 
      _completed = true; 
      if (_event != null) 
      { 
       _event.Set(); 
      } 
     } 

     _callback?.Invoke(this); 
    } 

    public bool IsCompleted 
    { 
     get { return _completed; } 
    } 

    public bool CompletedSynchronously 
    { 
     get { return _completedSynchronously; } 
    } 

    public object AsyncState 
    { 
     get { return _state; } 
    } 

    public WaitHandle AsyncWaitHandle 
    { 
     get 
     { 
      lock (_lock) 
      { 

       if (_event == null) 
       { 
        _event = new ManualResetEvent(IsCompleted); 
       } 
       return _event; 
      } 
     } 
    } 

} 
相關問題