Mono: IHttpAsyncHandler не вызывает EndProcessRequest

1

Я использую ASP.NET IHttpAsyncHandler для асинхронного перенаправления Long Polling HTTP Requsets на другой URL. Он отлично работает с.NET 4.5 (Windows 7,8). Но не работает с Mono (Mono JIT-компилятор версии 3.2.8 (Debian 3.2.8 + dfsg-4ubuntu1), Ubuntu 14.04). После завершения запроса.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. Я полагаю, что это поведение является ошибкой класса HttpWebRequest в среде Mono, но я не уверен. Могут ли быть какие-либо обходные пути этой проблемы?

  • 1
    Я не знаю ответа, но вы используете ужасно устаревшую технологию. Замените все эти вещи APM с async / await.
  • 0
    пожалуйста, отправьте сообщение об ошибке в bugzilla.xamarin.com с минимальным тестовым сценарием
Показать ещё 1 комментарий
Теги:
mono

1 ответ

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню