等待等待另一个 IAsyncResult 的 IAsyncResult 方法(链接)
(只能使用 .NET 3.5 stock,所以没有任务,没有响应式扩展)
我有,我认为这是一个简单的案例,但我对此感到困惑。
简而言之,我将 BeginGetRequestStream 的 IAsyncResult 返回给 BeginMyOperation() 的调用者,并且我想真正发送回 BeginGetResponse 的 IAsyncResult,该 IAsyncResult 在调用 EndGetRequestStream 时被调用。
所以我想知道我该如何
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);
}
(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);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我认为解决这个问题最简单的方法是使用
Task
包装器。特别是,您可以完成TaskCompletionSource
当BeginGetResponse
完成时。然后只需返回该TaskCompletionSource< 的
Task
/代码>。请注意,Task
实现了IAsyncResult
,因此您的客户端代码无需更改。就个人而言,我会更进一步:
BeginGetRequestStream
包装在Task
中(使用FromAsync
)。Task
创建一个延续,用于处理请求并将BeginGetResponse
包装在Task
中(再次使用FromAsync
) 。Task
创建一个延续,以完成TaskCompletionSource
。恕我直言,
Task
比IAsyncResult
更自然地处理异常和结果值。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
.您尝试做的事情是可行的,但您需要创建 IAsyncResult 的新实现(类似于“CompositeResult”,它监视第一个 IAsyncResult,然后启动第二个调用)。
然而,使用 Reactive Extensions 实际上这个任务要容易得多 - 在这种情况下,您可以使用 Observable.FromAsyncPattern 将 Begin/End 方法转换为返回 IObservable 的 Func(它也表示异步结果) ),然后使用 SelectMany 将它们链接起来:
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:
我意识到这个问题已经有将近一年的历史了,但是如果提问者的限制仍然存在,.NET 3.5 上有一个选项可以轻松地编写异步操作。查看 Jeff Richter 的 PowerThreading 库。在
Wintellect.PowerThreading.AsyncProgModel
命名空间中,您将找到AsyncEnumerator
类的多个变体,您可以将其与序列生成器一起使用来编写异步代码,就好像它是顺序代码一样。其要点是,您将异步代码编写为返回
IEnumerator
的序列生成器的主体,并且每当您调用异步方法时,您都会发出yield return
code> 包含要等待的异步操作的数量。图书馆处理血淋淋的细节。例如,要将一些数据发送到 url 并返回结果的内容:
如您所见,私有
PostData()
方法负责大部分工作。如三个yield return 1
语句所示,启动了三个异步方法。通过这种模式,您可以根据需要链接任意数量的异步方法,并且仍然只向调用者返回一个IAsyncResult
。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.我不太明白你想要实现什么,但我认为你应该重新考虑代码。
IAsyncResult 实例是允许处理异步方法调用的对象,它们是在您通过BeginXXX 执行异步调用时创建的。
在您的示例中,您基本上希望返回 IAsyncResult 的一个实例,该实例尚不存在。
我真的不知道您要解决的问题是什么,但也许这些方法之一更适合您:
希望它有帮助!
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!
首先,从 Jeffrey Richter 的 MSDN 杂志文章“实现 CLR 异步编程模型(2007 年 3 月号)。"
一旦有了这些基类,您就可以相对轻松地实现自己的异步结果。在此示例中,我将使用您的基本代码来启动 Web 请求,然后将响应作为由多个内部异步操作组成的单个异步操作来获取。
需要注意的一些事项:
异步编程并不是最简单的事情,但是一旦您理解了这些概念,它就会非常强大。
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.