Mono:IHttpAsyncHandler不调用EndProcessRequest

时间:2014-07-18 11:44:02

标签: c# asp.net mono

我使用ASP.NET IHttpAsyncHandler将异步重定向长轮询HTTP重新设置到其他URL。它与.NET 4.5(Windows 7,8)完美配合。但不适用于Mono(Mono JIT编译器版本3.2.8(Debian 3.2.8 + dfsg-4ubuntu1),Ubuntu 14.04)。完成request.BeginGetResponse后,AsyncCallback不会调用EndProcessRequest。

    public bool IsReusable { get { return true; } }

    public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
    {
        var request = (HttpWebRequest)HttpWebRequest.Create("http://www.google.com/");
        request.Method = context.Request.HttpMethod;

         request.UserAgent = context.Request.UserAgent;
        request.Accept = string.Join(",", context.Request.AcceptTypes);

        if (!string.IsNullOrEmpty(context.Request.Headers["Accept-Encoding"]))
        {
            request.Headers["Accept-Encoding"] = context.Request.Headers["Accept-Encoding"];
        }
        request.ContentType = context.Request.ContentType;
        request.ContentLength = context.Request.ContentLength;
        using (var stream = request.GetRequestStream())
        {
            CopyStream(context.Request.InputStream, stream);
        }
        return request.BeginGetResponse(cb, new object[] { context, request });
    }

    public void EndProcessRequest(IAsyncResult result)
    {

       // EndProcessRequest never called

        var context = (HttpContext)((object[])result.AsyncState)[0];
        var request = (HttpWebRequest)((object[])result.AsyncState)[1];
        using (var response = request.EndGetResponse(result))
        {
            context.Response.ContentType = response.ContentType;

            foreach (string h in response.Headers)
            {
                context.Response.AppendHeader(h, response.Headers[h]);
            }
            using (var stream = response.GetResponseStream())
            {
                CopyStream(stream, context.Response.OutputStream);
            }

            response.Close();
            context.Response.Flush();
        }
    }

    private void CopyStream(Stream from, Stream to)
    {
        var buffer = new byte[1024];
        while (true)
        {
            var read = from.Read(buffer, 0, buffer.Length);
            if (read == 0) break;

            to.Write(buffer, 0, read);
        }
    }

我不知道这个奇怪的beahaviour的原因。我想这种行为是Mono框架中HttpWebRequest类的错误,但我不确定。可能有这个问题的解决方法吗?

1 个答案:

答案 0 :(得分:0)

我们通过使用ThreadPool.QueueUserWorkItem找到了问题的一些解决方法:

    public bool IsReusable { get { return true; }}

    public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
    {
        return new AsynchOperation(cb, context, extraData).Start();
    }

    public void EndProcessRequest(IAsyncResult result) { }

    public void ProcessRequest(HttpContext context) { }

    private class AsynchOperation : IAsyncResult
    {
        private AsyncCallback cb;
        private HttpContext context;
        public WaitHandle AsyncWaitHandle { get { return null; } }
        public object AsyncState { get; private set; }
        public bool IsCompleted { get; private set; }
        public bool CompletedSynchronously { get { return false; } }

        public AsynchOperation(AsyncCallback callback, HttpContext context, object state)
        {
            cb = callback;
            this.context = context;
            AsyncState = state;
            IsCompleted = false;
        }

        public IAsyncResult Start()
        {
            ThreadPool.QueueUserWorkItem(AsyncWork, null);
            return this;
        }

        private void AsyncWork(object _)
        {
            var request = (HttpWebRequest)WebRequest.Create(boshUri);
            request.Method = context.Request.HttpMethod;

            // copy headers & body
            request.UserAgent = context.Request.UserAgent;
            request.Accept = string.Join(",", context.Request.AcceptTypes);
            if (!string.IsNullOrEmpty(context.Request.Headers["Accept-Encoding"]))
            {
                request.Headers["Accept-Encoding"] = context.Request.Headers["Accept-Encoding"];
            }
            request.ContentType = context.Request.ContentType;
            request.ContentLength = context.Request.ContentLength;

            using (var stream = request.GetRequestStream())
            {
                CopyStream(context.Request.InputStream, stream);
            }

            request.BeginGetResponse(EndGetResponse, Tuple.Create(context, request));
        }

        private void EndGetResponse(IAsyncResult ar)
        {
            var data = (Tuple<HttpContext, HttpWebRequest>)ar.AsyncState;
            var context = data.Item1;
            var request = data.Item2;

            try
            {
                using (var response = request.EndGetResponse(ar))
                {
                    context.Response.ContentType = response.ContentType;

                    // copy headers & body
                    foreach (string h in response.Headers)
                    {
                        context.Response.AppendHeader(h, response.Headers[h]);
                    }
                    using (var stream = response.GetResponseStream())
                    {
                        CopyStream(stream, context.Response.OutputStream);
                    }
                    context.Response.Flush();
                }
            }
            catch (Exception err)
            {
                if (err is IOException || err.InnerException is IOException)
                {
                    // ignore
                }
                else
                {
                    LogManager.GetLogger("ASC.Web.BOSH").Error(err);
                }
            }
            finally
            {
                IsCompleted = true;
                cb(this);
            }
        }