首页 文章

异步/等待调用asmx服务

提问于
浏览
2

我正在使用asmx服务并尝试在尝试调用时执行async / await

目前我的控制器如下

Public ActionResult Index()
{
   var data = _repository.GetDataFromAsmxService(somedata);
}

// RepositoryClass方法

public List<ObjectToReturn> GetDataFromAsmxService(somedata)
{
   var res = _asmxService.GetReportData(somedata);
   var result = process(res);
   return result;
}

在进一步查看生成的refrence.cs文件后,发现了等效调用的void async和onCompleted方法 .

所以我把它改成了

private void GetReportDataCallBack(object sender, GetReportDataCompletedEventArgs e)
        {
            var res = e.Result;
            var result = process(res);
        }

        public List<ObjectToReturn> GetDataFromAsmxService(somedata)
{
   _asmxService.GetReportDataCompleted +=GetReportDataCallBack;
   _asmxService.GetReportDataAsync(somedata);

}

但现在回调发生在Event委托上,所以我的控制器期望返回数据不会得到它 . what is a better way to call async/await from controller and get the data from asmx webservice

代码来自Refenrece.cs //生成的代码

[System.Web.Services.Protocols.SoapHeaderAttribute("ApiAuthenticationValue")]
        [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://webservice.com/GetReportData", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)]
        [return: System.Xml.Serialization.XmlElementAttribute(Namespace="http://webservice.com/")]
        public GetReportDataResponse GetReportData([System.Xml.Serialization.XmlElementAttribute(Namespace="http://webservice.com/")] GetReportDataRequest GetReportDataRequest) {
            object[] results = this.Invoke("GetReportData", new object[] {
                        GetReportDataRequest});
            return ((GetReportDataResponse)(results[0]));
        }

        /// <remarks/>
        public void GetReportDataAsync(GetReportDataRequest GetReportDataRequest) {
            this.GetReportDataAsync(GetReportDataRequest, null);
        }

        /// <remarks/>
        public void GetReportDataAsync(GetReportDataRequest GetReportDataRequest, object userState) {
            if ((this.GetReportDataOperationCompleted == null)) {
                this.GetReportDataOperationCompleted = new System.Threading.SendOrPostCallback(this.OnGetReportDataOperationCompleted);
            }
            this.InvokeAsync("GetReportData", new object[] {
                        GetReportDataRequest}, this.GetReportDataOperationCompleted, userState);
        }

        private void OnGetReportDataOperationCompleted(object arg) {
            if ((this.GetReportDataCompleted != null)) {
                System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg));
                this.GetReportDataCompleted(this, new GetReportDataCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState));
            }
        }

1 回答

  • 5

    你拥有的是Event-Based Asynchronous Pattern (EAP),你想要做的是wrap that up in a task所以你可以等待它 . 你通过TaskCompletionSource这样做 .

    public async Task<List<ObjectToReturn>> GetDataFromAsmxServiceAsync(GetReportDataRequest somedata)
    {
        var tcs = new TaskCompletionSource<GetReportDataResponse>();
        _asmxService.GetReportDataCompleted += GetReportDataCallBack;
        _asmxService.GetReportDataAsync(somedata, tcs); //we pass tcs in so it can be used from the callback.
        GetReportDataResponse res;
        try
        {
            res = await tcs.Task;
        }
        finally
        {
            //unsubscribe from the handler when done so we don't get a leak.
            _asmxService.GetReportDataCompleted -= GetReportDataCallBack;
        }
    
        var result = process(res);
        return result;
    }
    
    private void GetReportDataCallBack(object sender, GetReportDataCompletedEventArgs e)
    {
        var tcs = (TaskCompletionSource<GetReportDataResponse>)e.UserState;
        if (e.Cancelled)
        {
            tcs.TrySetCanceled();
        }
        else if (e.Error != null)
        {
            tcs.TrySetException(e.Error);
        }
        else
        {
            tcs.TrySetResult(e.Result);
        }
    }
    

    您还需要将控制器更改为异步

    public Task<ActionResult> IndexAsync()
    {
        var data = await _repository.GetDataFromAsmxServiceAsync(somedata);
    }
    

    Here is a good article解释了如何从同步MVC代码转换为异步MVC代码并解释了为什么即使 Index 现在被称为 IndexAsync 它仍然可以作为Index的控制器 .

相关问题