簡體   English   中英

如何在ASP.NET Web應用程序的IHttpHandler上實現隊列?

[英]How to implement a queue on a IHttpHandler in a ASP.NET Web app?

我有一個ASP.NET Web應用程序,該應用程序具有IHttpHandler來處理POST請求(基本上,它將處理JSON,然后將處理結果發送回客戶端)。

我想在我的應用程序中實現一個隊列系統,這樣,如果存在類似的發布請求,則不會並行處理它們,而是一個接一個地處理。

問題

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

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

謝謝 !

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

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;
            }
        }
    }

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM