首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >等待等待另一个IAsyncResult的IAsyncResult方法(链接)

等待等待另一个IAsyncResult的IAsyncResult方法(链接)
EN

Stack Overflow用户
提问于 2011-04-04 11:01:22
回答 5查看 3.8K关注 0票数 4

(只能使用.NET 3.5库存,因此没有任务,没有响应式扩展)

我有,我认为是一个简单的案例,但我对它感到困惑。

简而言之,我将BeginGetRequestStream的IAsyncResult返回给BeginMyOperation()的调用者,并且我希望真正返回BeginGetResponse的IAsyncResult,它在调用EndGetRequestStream时被调用。

所以我在想,我该怎么做

代码语言:javascript
复制
      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);
        }
EN

回答 5

Stack Overflow用户

发布于 2011-04-04 12:09:40

我认为解决这个问题最简单的方法是使用Task包装器。特别是,您可以在BeginGetResponse完成时完成TaskCompletionSource。然后返回Task for that TaskCompletionSource即可。请注意,Task实现了IAsyncResult,因此您的客户端代码不需要更改。

就我个人而言,我会更进一步:

  1. BeginGetRequestStream包装在Task中(使用FromAsync).
  2. Create作为处理请求的Task的延续,并将BeginGetResponse包装在Task中(同样,使用作为完成TaskCompletionSource.的第二个Task的延续

IAsyncResult相比,Task更自然地处理异常和结果值。

票数 3
EN

Stack Overflow用户

发布于 2011-04-04 12:00:28

您要做的事情是可行的,但您需要创建一个新的IAsyncResult实现(类似于"CompositeResult“,它监视第一个IAsyncResult,然后启动第二个调用)。

然而,使用反应式扩展实际上要容易得多-在这种情况下,您可以使用Observable.FromAsyncPattern将Begin/End方法转换为返回IObservable (也表示异步结果)的Func,然后使用SelectMany链接它们:

代码语言:javascript
复制
IObservable<Stream> GetRequestStream(string Url);
IObservable<bool> MyOperation(Stream stream);

GetRequestStream().SelectMany(x => MyOperation(x)).Subscribe(x => {
    // When everything is finished, this code will run
});
票数 2
EN

Stack Overflow用户

发布于 2012-04-16 09:17:50

我意识到这个问题已经有将近一年的历史了,但是如果请求者的限制仍然存在,那么在.NET 3.5上有一个选项可以轻松地组成异步操作。看看Jeff Richter的PowerThreading library。在Wintellect.PowerThreading.AsyncProgModel命名空间中,您将发现AsyncEnumerator类的几个变体,您可以将其与序列生成器一起使用来编写异步代码,就好像它是顺序的一样。

它的要点是,您将异步代码编写为返回IEnumerator<int>的序列生成器的主体,并且每当您调用异步方法时,您都会发出一个包含要等待的异步操作数量的yield return。这个库处理那些血淋淋的细节。

例如,将一些数据发布到url并返回结果的内容:

代码语言:javascript
复制
public IAsyncResult BeginPostData(string url, string content, AsyncCallback callback, object state)
{
    var ae = new AsyncEnumerator<string>();
    return ae.BeginExecute(PostData(ae, url, content), callback, state);
}

public string EndPostData(IAsyncResult result)
{
    var ae = AsyncEnumerator<string>.FromAsyncResult(result);
    return ae.EndExecute(result);
}

private IEnumerator<int> PostData(AsyncEnumerator<string> ae, string url, string content)
{
    var req = (HttpWebRequest)WebRequest.Create(url);
    req.Method = "POST";

    req.BeginGetRequestStream(ae.End(), null);
    yield return 1;

    using (var requestStream = req.EndGetRequestStream(ae.DequeAsyncResult()))
    {
        var bytes = Encoding.UTF8.GetBytes(content);
        requestStream.BeginWrite(bytes, 0, bytes.Length, ae.end(), null);
        yield return 1;

        requestStream.EndWrite(ae.DequeueAsyncResult());
    }

    req.BeginGetResponse(ae.End(), null);
    yield return 1;

    using (var response = req.EndGetResponse(ae.DequeueAsyncResult()))
    using (var responseStream = response.GetResponseStream())
    using (var reader = new StreamReader(responseStream))
    {
        ae.Result = reader.ReadToEnd();
    }
}

正如您所看到的,私有PostData()方法负责大部分工作。正如三个yield return 1语句所指示的那样,有三个异步方法被启动。使用这种模式,您可以链接任意多个异步方法,并且仍然只向调用者返回一个IAsyncResult

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5534193

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档