C# 在IHTTPassynchandler中同步调用Web服务

C# 在IHTTPassynchandler中同步调用Web服务,c#,web-services,C#,Web Services,我试图调用IHttpAsyncHandler中的Web服务,我发现有这样一个答案 我对答案有疑问。如果有人能帮助我,我将不胜感激 它有 Task webClientDownloadTask = webClientDownloadCompletionSource.Task; 我的问题是 Webclient DownloadCompletionSource与Webclient(客户端)对象无关,因此执行此操作的目的是什么: //获取TCS的任务,以便我们可以附加一些continuation Ta

我试图调用IHttpAsyncHandler中的Web服务,我发现有这样一个答案

我对答案有疑问。如果有人能帮助我,我将不胜感激

它有

Task webClientDownloadTask = webClientDownloadCompletionSource.Task;
我的问题是

  • Webclient DownloadCompletionSource与Webclient(客户端)对象无关,因此执行此操作的目的是什么:

    //获取TCS的任务,以便我们可以附加一些continuation Task webClientDownloadTask=webClientDownloadCompletionSource.Task

  • 这里的“taskCompletionSource”是什么:

  • 为什么我要在ContinueWith()回调中dispose()WebClient,为什么不在设置taskCompletionSource.SetResult(true)

    //工作完成后,务必处置客户 webClientDownloadTask.ContinueWith( _ => { client.Dispose(); }, TaskContinuationOptions.ExecuteSynchronously)

  • 以下是完整的代码:

        public class MyAsyncHandler : IHttpAsyncHandler
    {
        public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
        {
            // NOTE: the result of this operation is void, but TCS requires some data type so we just use bool
            TaskCompletionSource<bool> webClientDownloadCompletionSource = new TaskCompletionSource<bool>();
    
            WebClient webClient = new WebClient())
            HttpContext currentHttpContext = HttpContext.Current;
    
            // Setup the download completed event handler
            client.DownloadDataCompleted += (o, e) =>
            {
                if(e.Cancelled)
                {
                    // If it was canceled, signal the TCS is cacnceled
                    // NOTE: probably don't need this since you have nothing canceling the operation anyway
                    webClientDownloadCompletionSource.SetCanceled();
                }
                else if(e.Error != null)
                {
                    // If there was an exception, signal the TCS with the exception
                    webClientDownloadCompletionSource.SetException(e.Error);
                }
                else
                {
                    // Success, write the response
                    currentHttpContext.Response.ContentType = "text/xml";
                    currentHttpContext.Response.OutputStream.Write(e.Result, 0, e.Result.Length);
    
                    // Signal the TCS that were done (we don't actually look at the bool result, but it's needed)
                    taskCompletionSource.SetResult(true);
                }
            };
    
            string url = "url_web_service_url";
    
            // Kick off the download immediately
            client.DownloadDataAsync(new Uri(url));
    
            // Get the TCS's task so that we can append some continuations
            Task webClientDownloadTask = webClientDownloadCompletionSource.Task;
    
            // Always dispose of the client once the work is completed
            webClientDownloadTask.ContinueWith(
                _ =>
                {
                    client.Dispose();
                },
                TaskContinuationOptions.ExecuteSynchronously);
    
            // If there was a callback passed in, we need to invoke it after the download work has completed
            if(cb != null)
            {
                webClientDownloadTask.ContinueWith(
                   webClientDownloadAntecedent =>
                   {
                       cb(webClientDownloadAntecedent);
                   },
                   TaskContinuationOptions.ExecuteSynchronously);
             }
    
            // Return the TCS's Task as the IAsyncResult
            return webClientDownloadTask;
        }
    
        public void EndProcessRequest(IAsyncResult result)
        {
            // Unwrap the task and wait on it which will propagate any exceptions that might have occurred
            ((Task)result).Wait();
        }
    
        public bool IsReusable
        {
            get 
            { 
                return true; // why not return true here? you have no state, it's easily reusable!
            }
        }
    
        public void ProcessRequest(HttpContext context)
        {
        }
    }
    
    公共类MyAsyncHandler:IHTTPassynchandler
    {
    公共IAsyncResult BeginProcessRequest(HttpContext上下文、AsyncCallback cb、object extraData)
    {
    //注意:这个操作的结果是void,但是TCS需要一些数据类型,所以我们只使用bool
    TaskCompletionSource webClientDownloadCompletionSource=新TaskCompletionSource();
    WebClient WebClient=新的WebClient()
    HttpContext currentHttpContext=HttpContext.Current;
    //设置下载完成的事件处理程序
    client.DownloadDataCompleted+=(o,e)=>
    {
    如果(如已取消)
    {
    //如果取消,则向TCS发送取消信号
    //注意:可能不需要这个,因为您没有任何取消操作的方法
    webClientDownloadCompletionSource.setCancelled();
    }
    否则如果(例如错误!=null)
    {
    //如果出现异常,则向TCS发送异常信号
    webClientDownloadCompletionSource.SetException(e.Error);
    }
    其他的
    {
    //成功,写下回应
    currentHttpContext.Response.ContentType=“text/xml”;
    currentHttpContext.Response.OutputStream.Write(e.Result,0,e.Result.Length);
    //向已完成的TCS发送信号(我们实际上没有查看bool结果,但这是必需的)
    taskCompletionSource.SetResult(true);
    }
    };
    string url=“url\u web\u service\u url”;
    //立即开始下载
    DownloadDataAsync(新Uri(url));
    //获取TCS的任务,以便我们可以附加一些continuation
    Task webClientDownloadTask=webClientDownloadCompletionSource.Task;
    //工作完成后,务必处置客户
    webClientDownloadTask.ContinueWith(
    _ =>
    {
    client.Dispose();
    },
    TaskContinuationOptions.ExecuteSynchronously);
    //如果传入了回调,我们需要在下载工作完成后调用它
    如果(cb!=null)
    {
    webClientDownloadTask.ContinueWith(
    webClientDownloadAntecedent=>
    {
    cb(网络客户端下载先行项);
    },
    TaskContinuationOptions.ExecuteSynchronously);
    }
    //将TCS的任务作为IAsyncResult返回
    返回webClientDownloadTask;
    }
    公共无效EndProcessRequest(IAsyncResult结果)
    {
    //展开任务并等待它,这将传播可能发生的任何异常
    ((任务)结果)。等待();
    }
    公共布尔可重用
    {
    得到
    { 
    return true;//为什么不在这里返回true?您没有状态,它很容易重用!
    }
    }
    公共void ProcessRequest(HttpContext上下文)
    {
    }
    }
    
    查看此项了解其用途。最后还有一个例子

    在许多情况下,启用任务来表示 外部异步操作TaskCompletionSource{TResult} 为此目的而提供。它允许创建一个可以 分发给消费者,这些消费者可以使用 这项任务和其他任务一样重要。但是,与大多数任务不同的是 TaskCompletionSource创建的任务的状态受控制 由TaskCompletionSource上的方法显式执行。这使得 完成要传播到的外部异步操作 基本任务。这种分离还确保消费者 无法在不访问相应服务器的情况下转换状态 TaskCompletionSource

        public class MyAsyncHandler : IHttpAsyncHandler
    {
        public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
        {
            // NOTE: the result of this operation is void, but TCS requires some data type so we just use bool
            TaskCompletionSource<bool> webClientDownloadCompletionSource = new TaskCompletionSource<bool>();
    
            WebClient webClient = new WebClient())
            HttpContext currentHttpContext = HttpContext.Current;
    
            // Setup the download completed event handler
            client.DownloadDataCompleted += (o, e) =>
            {
                if(e.Cancelled)
                {
                    // If it was canceled, signal the TCS is cacnceled
                    // NOTE: probably don't need this since you have nothing canceling the operation anyway
                    webClientDownloadCompletionSource.SetCanceled();
                }
                else if(e.Error != null)
                {
                    // If there was an exception, signal the TCS with the exception
                    webClientDownloadCompletionSource.SetException(e.Error);
                }
                else
                {
                    // Success, write the response
                    currentHttpContext.Response.ContentType = "text/xml";
                    currentHttpContext.Response.OutputStream.Write(e.Result, 0, e.Result.Length);
    
                    // Signal the TCS that were done (we don't actually look at the bool result, but it's needed)
                    taskCompletionSource.SetResult(true);
                }
            };
    
            string url = "url_web_service_url";
    
            // Kick off the download immediately
            client.DownloadDataAsync(new Uri(url));
    
            // Get the TCS's task so that we can append some continuations
            Task webClientDownloadTask = webClientDownloadCompletionSource.Task;
    
            // Always dispose of the client once the work is completed
            webClientDownloadTask.ContinueWith(
                _ =>
                {
                    client.Dispose();
                },
                TaskContinuationOptions.ExecuteSynchronously);
    
            // If there was a callback passed in, we need to invoke it after the download work has completed
            if(cb != null)
            {
                webClientDownloadTask.ContinueWith(
                   webClientDownloadAntecedent =>
                   {
                       cb(webClientDownloadAntecedent);
                   },
                   TaskContinuationOptions.ExecuteSynchronously);
             }
    
            // Return the TCS's Task as the IAsyncResult
            return webClientDownloadTask;
        }
    
        public void EndProcessRequest(IAsyncResult result)
        {
            // Unwrap the task and wait on it which will propagate any exceptions that might have occurred
            ((Task)result).Wait();
        }
    
        public bool IsReusable
        {
            get 
            { 
                return true; // why not return true here? you have no state, it's easily reusable!
            }
        }
    
        public void ProcessRequest(HttpContext context)
        {
        }
    }