(can only use .NET 3.5 stock, so no Tasks, no Reactive Extensions)
I have, what I thought to be a simple case, but I'm baffled at it.
The short of it is that, I'm returning BeginGetRequestStream's IAsyncResult to the caller of BeginMyOperation(), and I want to really send back the IAsyncResult of BeginGetResponse, which is called when the EndGetRequestStream is called.
So I'm wondering, how do I
public IAsyncResult BeginMyOperation(...)
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(requestUri);
webRequest.Method = "POST";
// This is the part, that puzzles me. I don't want to send this IAsyncResult back.
return webRequest.BeginGetRequestStream(this.UploadingStreamCallback, state);
}
// Only want this to be called when the EndGetResponse is ready.
public void EndMyOperation(IAsyncResult ar)
{
}
private IAsyncResult UploadingStreamCallback(IAsyncResult asyncResult)
{
using (var s = state.WebRequest.EndGetRequestStream(asyncResult))
{
using (var r = new BinaryReader(state.Request.RequestData))
{
byte[] uploadBuffer = new byte[UploadBufferSize];
int bytesRead;
do
{
bytesRead = r.Read(uploadBuffer, 0, UploadBufferSize);
if (bytesRead > 0)
{
s.Write(uploadBuffer, 0, bytesRead);
}
}
while (bytesRead > 0);
}
}
// I really want to return this IAsyncResult to the caller of BeginMyOperation
return state.WebRequest.BeginGetResponse(new AsyncCallback(state.Callback), state);
}
I don't really understand what are you trying to achieve, but I think you should be rethinking the code. An IAsyncResult instance is the object that allows to to handle asynchronous method calls, and they are created when you perform an async call through BeginXXX.
In your example, you basically want to return an instance of an IAsyncResult that it doesn't exist yet.
I don't really know which is the problem you are trying to solve, but maybe one of these approaches work better for you:
Hope it helps!
First, get the
AsyncResultNoResult
andAsyncResult<TResult>
implementation code from Jeffrey Richter's MSDN magazine article "Implementing the CLR Asynchronous Programming Model (March 2007 issue)."Once you have those base classes, you can relatively easily implement your own async result. In this example, I will use your basic code to start the web request and then get the response as a single async operation composed of multiple inner async operations.
Some things to note:
Asynchronous programming is not the simplest thing but it is very powerful once you understand the concepts.
I think the easiest way to solve this is to use
Task
wrappers. In particular, you can finish aTaskCompletionSource
whenBeginGetResponse
completes. Then just return theTask
for thatTaskCompletionSource
. Note thatTask
implementsIAsyncResult
, so your client code won't have to change.Personally, I would go a step further:
BeginGetRequestStream
in aTask
(usingFromAsync
).Task
that processes the request and wrapsBeginGetResponse
in aTask
(again, usingFromAsync
).Task
that completes theTaskCompletionSource
.IMHO, exceptions and result values are more naturally handled by
Task
s thanIAsyncResult
.The thing you're trying to do is doable, but you need to create a new implementation of IAsyncResult (something like "CompositeResult" that watches the first IAsyncResult, then kicks off the 2nd call).
However, this task is actually far easier using the Reactive Extensions - in that case you'd use Observable.FromAsyncPattern to convert your Begin/End methods into a Func that returns IObservable (which also represents an async result), then chain them using SelectMany:
I realize that this question is almost one year old, but if the constraints of the asker still hold, there is an option available on .NET 3.5 to easily compose asynchronous operations. Look at Jeff Richter's PowerThreading library. In the
Wintellect.PowerThreading.AsyncProgModel
namespace, you will find several variants of theAsyncEnumerator
class, which you can use with sequence generators to write async code as if it were sequential.The gist of it is that you write your async code as the body of a sequence generator that returns an
IEnumerator<int>
, and whenever you call an async method you issue ayield return
with the number of async operations to wait for. The library handles the gory details.For example, to post some data to a url and return the contents of the result:
As you can see, the private
PostData()
method is responsible for the bulk of the work. There are three async methods kicked off, as indicated by the threeyield return 1
statements. With this pattern, you can chain as many async methods as you'd like and still just return oneIAsyncResult
to the caller.