Re[3]: Сделайте плиз ревью кода (HttpWebRequest& Async IO)
От: desco США http://v2matveev.blogspot.com
Дата: 24.10.08 20:10
Оценка: 4 (1) :)
Здравствуйте, Tom, Вы писали:

<skipped/>

очень облегчает жизнь у нас, правда, использовался свой вспомогательный класс типа такого:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Text;
using System.Threading;

class AsyncHelper
{
    private IEnumerator<Action> enumerator;
    private readonly ManualResetEvent waitHandle = new ManualResetEvent(false);
    public IAsyncResult AsyncResult { get; private set;}

    public WaitHandle WaitHandle
    {
        get { return waitHandle; }
    }

    public void Execute(IEnumerable<Action> enumerable)
    {
        enumerator = enumerable.GetEnumerator();
        AsyncResult = null;
        MoveNext();
    }

    public void Next(IAsyncResult ar)
    {
        if (ar == null)
            throw new ArgumentNullException("ar");

        AsyncResult = ar;
        MoveNext();
    }

    private void MoveNext()
    {
        if (enumerator.MoveNext())
            enumerator.Current();
        else
            waitHandle.Set();
    }
}

class Program
{
    static void Main()
    {
        var helper = new AsyncHelper();
        helper.Execute(AsyncHttpTest(helper));
        helper.WaitHandle.WaitOne();
    }

    private static IEnumerable<Action> AsyncHttpTest(AsyncHelper asyncHelper)
    {
        var webRequest = (HttpWebRequest)WebRequest.Create("http://AAA.BBB.CCC");

        webRequest.Method = WebRequestMethods.Http.Post;
        webRequest.ContentType = "text/xml";
        webRequest.Timeout = 1000;

        var requestData = Encoding.ASCII.GetBytes("@@@@@@@@@");
        webRequest.ContentLength = requestData.Length;

        yield return () => webRequest.BeginGetRequestStream(asyncHelper.Next, null);
        using (var stream = webRequest.EndGetRequestStream(asyncHelper.AsyncResult))
        {
            yield return () => stream.BeginWrite(requestData, 0, requestData.Length, asyncHelper.Next, null);
            stream.EndWrite(asyncHelper.AsyncResult);

            yield return () => webRequest.BeginGetResponse(asyncHelper.Next, null);
            var response = (HttpWebResponse)webRequest.EndGetResponse(asyncHelper.AsyncResult);

            var responseData = new byte[response.ContentLength];
            using (var responseStream = response.GetResponseStream())
            {
                yield return () => responseStream.BeginRead(responseData, 0, responseData.Length, asyncHelper.Next, null);
                var read = responseStream.EndRead(asyncHelper.AsyncResult);
                Trace.TraceInformation(Encoding.ASCII.GetString(responseData));
            }
        }
    }
}
Re: Сделайте плиз ревью кода (HttpWebRequest& Async IO)
От: drol  
Дата: 06.10.08 01:14
Оценка: +1
Здравствуйте, Tom, Вы писали:

А вот это не пробовали использовать ? Результат будет гораздо короче, проще и понятнее
Сделайте плиз ревью кода (HttpWebRequest& Async IO)
От: Tom Россия http://www.RSDN.ru
Дата: 05.10.08 10:41
Оценка:
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Threading;
using System.Diagnostics;

namespace AsyncHttpTest
{
    public class RequestState
    {
        public byte[] requestData;
        public byte[] responseData;

        public HttpWebRequest request;
        public HttpWebResponse response;

        public Stream streamRequest;
        public Stream streamResponse;

        public ManualResetEvent timeoutEvent;
        public bool requestAborted;

        /// <summary>
        /// Close all resources like streams, events...
        /// </summary>
        public void Close()
        {
            try
            {
                timeoutEvent.Close();
                streamRequest.Close();
                streamResponse.Close();
                response.Close();

                //
                // Null all fields to simplify debugging.
                //
                requestData = null;
                responseData = null;

                request = null;
                response = null;

                streamRequest = null;
                streamResponse = null;

                timeoutEvent = null;
            }
            catch (Exception e)
            {
                Trace.TraceError(e.ToString());
            }
        }
    }

    class Program
    {
        private static int RequestTimeout = 10000;

        private static void TimeoutCallback(object state, bool timedOut)
        {
            Trace.TraceInformation(
                "TimeoutCallback, timedOut={0}",
                timedOut);

            try
            {
                RequestState requestState = (RequestState)state;

                lock (requestState)
                {
                    if (timedOut)
                    {
                        requestState.requestAborted = true;

                        requestState.request.Abort();
                    }

                    requestState.Close();
                }
            }
            catch (Exception e)
            {
                Trace.TraceError(e.ToString());
            }
        }

        static void Main()
        {

            try
            {
                HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("http://AAA.BBB.CCC");

                webRequest.Method = "POST";
                webRequest.ContentType = "text/xml";
                webRequest.Timeout = RequestTimeout;

                RequestState requestState = new RequestState();
                requestState.request = webRequest;
                requestState.timeoutEvent = new ManualResetEvent(false);

                requestState.requestData = Encoding.ASCII.GetBytes("@@@@@@@@@");
                requestState.request.ContentLength = requestState.requestData.Length;

                ThreadPool.RegisterWaitForSingleObject(
                    requestState.timeoutEvent,
                    new WaitOrTimerCallback(TimeoutCallback),
                    requestState,
                    RequestTimeout,
                    true);

                webRequest.BeginGetRequestStream(
                    new AsyncCallback(BeginGetRequestStreamCallback),
                    requestState);

                Console.WriteLine("press any key to exit...");
                Console.ReadKey();
            }
            catch (Exception e)
            {
                Trace.TraceError(e.ToString());
            }
        }

        private static void BeginGetRequestStreamCallback(
            IAsyncResult asynchronousResult)
        {
            Trace.TraceInformation(
                "BeginGetRequestStreamCallback, IsCompleted={0}, CompletedSynchronously={1}",
                asynchronousResult.IsCompleted,
                asynchronousResult.CompletedSynchronously);

            try
            {
                RequestState requestState = (RequestState)asynchronousResult.AsyncState;

                lock (requestState)
                {
                    if (requestState.requestAborted == true)
                    {
                        Trace.TraceInformation(
                            "BeginGetRequestStreamCallback, requestAborted=true");

                        return;
                    }

                    requestState.streamRequest = requestState.request.EndGetRequestStream(
                        asynchronousResult);

                    requestState.streamRequest.BeginWrite(
                        requestState.requestData,
                        0,
                        requestState.requestData.Length,
                        new AsyncCallback(RequestWriteCallBack),
                        requestState);
                }
            }
            catch (Exception e)
            {
                Trace.TraceError(e.ToString());
            }
        }

        private static void RequestWriteCallBack(
            IAsyncResult asynchronousResult)
        {
            Trace.TraceInformation(
                "RequestWriteCallBack, IsCompleted={0}, CompletedSynchronously={1}",
                asynchronousResult.IsCompleted,
                asynchronousResult.CompletedSynchronously);

            try
            {
                RequestState requestState = (RequestState)asynchronousResult.AsyncState;

                lock (requestState)
                {
                    if (requestState.requestAborted == true)
                    {
                        Trace.TraceInformation(
                            "RequestWriteCallBack, requestAborted=true");

                        return;
                    }

                    requestState.streamRequest.EndWrite(
                        asynchronousResult);

                    requestState.request.BeginGetResponse(
                        new AsyncCallback(BeginGetResponseCallback),
                        requestState);
                }
            }
            catch (Exception e)
            {
                Trace.TraceError(e.ToString());
            }
        }

        private static void BeginGetResponseCallback(
            IAsyncResult asynchronousResult)
        {
            Trace.TraceInformation(
                "BeginGetResponseCallback, IsCompleted={0}, CompletedSynchronously={1}",
                asynchronousResult.IsCompleted,
                asynchronousResult.CompletedSynchronously);

            try
            {
                RequestState requestState = (RequestState)asynchronousResult.AsyncState;

                lock (requestState)
                {
                    if (requestState.requestAborted == true)
                    {
                        Trace.TraceInformation(
                            "BeginGetResponseCallback, requestAborted=true");

                        return;
                    }

                    requestState.response = (HttpWebResponse)requestState.request.EndGetResponse(
                        asynchronousResult);

                    //
                    // TODO: Check response status and begin asynchronous read only if valid status
                    //

                    requestState.streamResponse = requestState.response.GetResponseStream();
                    requestState.responseData = new byte[requestState.response.ContentLength];

                    requestState.streamResponse.BeginRead(
                        requestState.responseData,
                        0,
                        requestState.responseData.Length,
                        new AsyncCallback(ResponseReadCallBack),
                        requestState);
                }
            }
            catch (Exception e)
            {
                Trace.TraceError(e.ToString());
            }
        }

        private static void ResponseReadCallBack(
            IAsyncResult asynchronousResult)
        {
            Trace.TraceInformation(
                "ResponseReadCallBack, IsCompleted={0}, CompletedSynchronously={1}",
                asynchronousResult.IsCompleted,
                asynchronousResult.CompletedSynchronously);

            try
            {
                RequestState requestState = (RequestState)asynchronousResult.AsyncState;

                lock (requestState)
                {
                    if (requestState.requestAborted == true)
                    {
                        Trace.TraceInformation(
                            "ResponseReadCallBack, requestAborted=true");

                        return;
                    }

                    int bytesRead = requestState.streamResponse.EndRead(asynchronousResult);

                    //
                    // TODO: Not whole response could be read, we need check amount of data read and
                    //       begin new asynchronous read if needed using corresponding offset in the buffer.
                    //
                    Trace.TraceInformation(Encoding.ASCII.GetString(requestState.responseData));

                    requestState.timeoutEvent.Set();
                }
            }
            catch (Exception e)
            {
                Trace.TraceError(e.ToString());
            }
        }
    }
}
Народная мудрось
всем все никому ничего(с).
Re: Сделайте плиз ревью кода (HttpWebRequest& Async IO)
От: vdimas Россия  
Дата: 05.10.08 16:58
Оценка:
Здравствуйте, Tom, Вы писали:

Дело вкуса, но всё, до вызова GetResponseStream и затем закачки самих данных, вполне можно было сделать синхронно.
... << RSDN@Home 1.2.0 alpha rev. 786>>
Re[2]: Сделайте плиз ревью кода (HttpWebRequest& Async IO)
От: Tom Россия http://www.RSDN.ru
Дата: 06.10.08 10:29
Оценка:
Здравствуйте, drol, Вы писали:

D>Здравствуйте, Tom, Вы писали:


D>А вот это не пробовали использовать ? Результат будет гораздо короче, проще и понятнее



In this column, I introduce my AsyncEnumerator class, which intelligently drives an iterator so that different thread pool threads can execute the code at different times, and I ensure that the iterator only advances after asynchronous I/O operations complete. I am also going to explain the architecture of my AsyncEnumerator class and how it works.


А мой случай тут причём? Можешь пояснить?
Народная мудрось
всем все никому ничего(с).
Re[3]: Сделайте плиз ревью кода (HttpWebRequest& Async IO)
От: Sinclair Россия https://github.com/evilguest/
Дата: 06.10.08 10:55
Оценка:
Здравствуйте, Tom, Вы писали:
Tom>А мой случай тут причём? Можешь пояснить?
Твой случай при том, что ты вручную пишешь код, который бы за тебя сгенерировал компилятор. В статье приведен пример использования енумератора для асинхронной обработки веб-реквестов. Кода с его использованием будет меньше в несколько раз, чем написано у тебя.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: Сделайте плиз ревью кода (HttpWebRequest& Async IO)
От: TK Лес кывт.рф
Дата: 25.10.08 08:50
Оценка:
Здравствуйте, Tom, Вы писали:

Ужас какой-то... 300 строк кода только на то, чтобы послать асинхронно POSTом запрос и получить ответ (правда, может это и не так — без поллитра сразу не видно)? Да и на .NET 2.0 стоило бы перейти — вышел он уже совсем давно.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[2]: Сделайте плиз ревью кода (HttpWebRequest& Async IO)
От: Tom Россия http://www.RSDN.ru
Дата: 25.10.08 09:34
Оценка:
TK>Ужас какой-то... 300 строк кода только на то, чтобы послать асинхронно POSTом запрос и получить ответ (правда, может это и не так — без поллитра сразу не видно)? Да и на .NET 2.0 стоило бы перейти — вышел он уже совсем давно.
Непонял, а чем указанный код не .NET 2.0? У маня как раз нет ограничения на фреймворк, можно что то из 3.5 использвать если надо. А по поводу ужаса, незнаю даже, оно предельно понятно и легко отлаживается, что важно для продакшин кода. Можно предложения по упрощению?
Народная мудрось
всем все никому ничего(с).
Re[4]: Сделайте плиз ревью кода (HttpWebRequest& Async IO)
От: Tom Россия http://www.RSDN.ru
Дата: 25.10.08 09:35
Оценка:
Незнаю, для меня этот код хоть и короче, но на порядок менее четабельно понимабельный.
Народная мудрось
всем все никому ничего(с).
Re: Сделайте плиз ревью кода (HttpWebRequest& Async IO)
От: Аноним  
Дата: 25.10.08 13:57
Оценка:
Здравствуйте, Tom, Вы писали:

...

натравить пробовали?
Re: Сделайте плиз ревью кода (HttpWebRequest& Async IO)
От: Константин Л.  
Дата: 25.10.08 14:38
Оценка:
Здравствуйте, Tom, Вы писали:

[]

ну хоть как-то так (про повторное использование иодно и того же инстанса etc. сильно не думал):

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Threading;
using System.Diagnostics;
using System.Linq;

namespace cs_console
{
    public sealed class AsyncRequest
    {
        //private readonly object _sync = new object();

        public byte[] requestData { get; private set; }
        public byte[] responseData { get; private set; }

        HttpWebRequest request { get; set; }
        public HttpWebResponse response { get; private set; }

        public Stream streamRequest { get; private set; }
        public Stream streamResponse { get; private set; }

        ManualResetEvent timeoutEvent { get; set; }

        private volatile bool _requestAborted = false;

        public bool requestAborted { get { return _requestAborted; } }

        public AsyncRequest(HttpWebRequest request, byte[] requestData)
        {
            this.request = request;

            this.requestData = requestData;
            this.request.ContentLength = this.requestData.Length;

            this.timeoutEvent = new ManualResetEvent(false); 
            
        }

        /// <summary>
        /// Close all resources like streams, events...
        /// </summary>
        void Close()
        {
            try
            {
                timeoutEvent.Close();
                streamRequest.Close();
                streamResponse.Close();
                response.Close();

                //
                // Null all fields to simplify debugging.
                //
                requestData = null;
                responseData = null;

                request = null;
                response = null;

                streamRequest = null;
                streamResponse = null;

                timeoutEvent = null;
            }
            catch (Exception e)
            {
                Trace.TraceError(e.ToString());
            }
        }

        void Dispose(bool disposing)
        {
            if (disposing)
            {
                Close();
                GC.SuppressFinalize(this);
            }
            else Close();
        }

        ~AsyncRequest()
        {
            Dispose(false);
        }

        private void OnBeginGetRequestStream(
            IAsyncResult asynchronousResult)
        {
            try
            {
                //lock (_sync)
                {
                    if (requestAborted == true) return;

                    streamRequest = request.EndGetRequestStream(
                        asynchronousResult);

                    streamRequest.BeginWrite(
                        requestData,
                        0,
                        requestData.Length,
                        this.OnRequestWrite,
                        null);
                }
            }
            catch (Exception e)
            {
                Trace.TraceError(e.ToString());
            }
        }

        private void OnRequestWrite(
            IAsyncResult asynchronousResult)
        {
            try
            {
                //lock (_sync)
                {
                    if (requestAborted == true)
                        return;

                    streamRequest.EndWrite(asynchronousResult);

                    request.BeginGetResponse(this.OnBeginGetResponse, null);
                }
            }
            catch (Exception e)
            {
                Trace.TraceError(e.ToString());
            }
        }

        private void OnBeginGetResponse(
            IAsyncResult asynchronousResult)
        {
            try
            {
                //lock (_sync)
                {
                    if (requestAborted == true)
                        return;

                    response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);

                    streamResponse = response.GetResponseStream();
                    responseData = new byte[response.ContentLength];

                    streamResponse.BeginRead(
                        responseData,
                        0,
                        responseData.Length,
                        this.OnResponseRead,
                        null);
                }
            }
            catch (Exception e)
            {
                Trace.TraceError(e.ToString());
            }
        }

        private void OnResponseRead(
            IAsyncResult asynchronousResult)
        {
            try
            {
                //lock (_sync)
                {
                    if (requestAborted == true)
                        return;

                    int bytesRead = streamResponse.EndRead(asynchronousResult);

                    timeoutEvent.Set();
                }
            }
            catch (Exception e)
            {
                Trace.TraceError(e.ToString());
            }
        }

        private void OnTimeout(object state, bool timedOut)
        {   
            try
            {
                //lock (_sync)
                {
                    if (timedOut)
                    {
                        _requestAborted = true;
                        request.Abort();
                    }

                    this.Dispose(true);
                }
            }
            catch (Exception e)
            {
                Trace.TraceError(e.ToString());
            }
        }

        public void Begin()
        {
            if (requestAborted) throw new ObjectDisposedException("this"); //???

            ThreadPool.RegisterWaitForSingleObject(
                        this.timeoutEvent,
                        OnTimeout,
                        this,
                        request.Timeout,
                        true);

            request.BeginGetRequestStream(
                        this.OnBeginGetRequestStream,
                        null);
        }
    }

    class Program
    {
        private static int RequestTimeout = 1000000;        

        static void Main()
        {

            try
            {
                HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("http://www.rsdn.ru");

                webRequest.Method = "POST";
                webRequest.ContentType = "text/xml";
                webRequest.Timeout = RequestTimeout;

                var request = new AsyncRequest(webRequest, Encoding.ASCII.GetBytes("@@@@@@@@@"));
                {
                    request.Begin();

                    Console.WriteLine("press any key to exit...");
                    Console.ReadKey();
                }
            }
            catch (Exception e)
            {
                Trace.TraceError(e.ToString());
            }
        }

        
    }
}



lock там, имхо, не нужен
Re[3]: Сделайте плиз ревью кода (HttpWebRequest& Async IO)
От: TK Лес кывт.рф
Дата: 25.10.08 16:13
Оценка:
Здравствуйте, Tom, Вы писали:

Tom>А по поводу ужаса, незнаю даже, оно предельно понятно и легко отлаживается, что важно для продакшин кода. Можно предложения по упрощению?


ИХМО, плохо то, что реализация получилось размазанной по куче методов.... плюс, с логгированием вызовов стоило бы что-то сделать — оно занимает добрую часть кода. хотя, это дела вкуса :) в остальном, то что написал desco выглядит более понятным (код в AsyncHttpTest, а не AsyncHelper — это уже слишком :)
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.