Сделайте плиз ревью кода (HttpWebRequest& Async IO)
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: Сделайте плиз ревью кода (HttpWebRequest& Async IO)
От:
drol
Дата: 06.10.08 01:14
Оценка:
+1
Здравствуйте, Tom, Вы писали:
А
вот это не пробовали использовать ? Результат будет гораздо короче, проще и понятнее
Re[2]: Сделайте плиз ревью кода (HttpWebRequest& Async IO)
Здравствуйте, 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)
Здравствуйте, Tom, Вы писали:
Tom>А мой случай тут причём? Можешь пояснить?
Твой случай при том, что ты вручную пишешь код, который бы за тебя сгенерировал компилятор. В статье приведен пример использования енумератора для асинхронной обработки веб-реквестов. Кода с его использованием будет меньше в несколько раз, чем написано у тебя.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: Сделайте плиз ревью кода (HttpWebRequest& Async IO)
Здравствуйте, 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)
Здравствуйте, Tom, Вы писали:
Ужас какой-то... 300 строк кода только на то, чтобы послать асинхронно POSTом запрос и получить ответ (правда, может это и не так — без поллитра сразу не видно)? Да и на .NET 2.0 стоило бы перейти — вышел он уже совсем давно.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[2]: Сделайте плиз ревью кода (HttpWebRequest& Async IO)
TK>Ужас какой-то... 300 строк кода только на то, чтобы послать асинхронно POSTом запрос и получить ответ (правда, может это и не так — без поллитра сразу не видно)? Да и на .NET 2.0 стоило бы перейти — вышел он уже совсем давно.
Непонял, а чем указанный код не .NET 2.0? У маня как раз нет ограничения на фреймворк, можно что то из 3.5 использвать если надо. А по поводу ужаса, незнаю даже, оно предельно понятно и легко отлаживается, что важно для продакшин кода. Можно предложения по упрощению?
Народная мудрось
всем все никому ничего(с).
Re[4]: Сделайте плиз ревью кода (HttpWebRequest& Async IO)
Незнаю, для меня этот код хоть и короче, но на порядок менее четабельно понимабельный.
Народная мудрось
всем все никому ничего(с).
Re: Сделайте плиз ревью кода (HttpWebRequest& Async IO)
От:
Аноним
Дата: 25.10.08 13:57
Оценка:
Здравствуйте, Tom, Вы писали:
...
натравить пробовали?
Re: Сделайте плиз ревью кода (HttpWebRequest& Async IO)
Здравствуйте, 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)
Здравствуйте, Tom, Вы писали:
Tom>А по поводу ужаса, незнаю даже, оно предельно понятно и легко отлаживается, что важно для продакшин кода. Можно предложения по упрощению?
ИХМО, плохо то, что реализация получилось размазанной по куче методов.... плюс, с логгированием вызовов стоило бы что-то сделать — оно занимает добрую часть кода. хотя, это дела вкуса :) в остальном, то что написал desco выглядит более понятным (код в AsyncHttpTest, а не AsyncHelper — это уже слишком :)
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Пока на собственное сообщение не было ответов, его можно удалить.
Удалить