【发布时间】:2015-07-13 17:08:45
【问题描述】:
我正在编写一个 ASP.NET MVC 5 应用程序,其中使用 Web 服务来获取/处理一些数据。
应用程序的数据流如下:MVC Action -> Service B -> ExtSvc,它是 Web 服务的异步包装器
这里有一些例子:
public class ExtSvc
{
//Convert Event based async pattern to task based async pattern:
private Task<Response> ProcessExtRequestAsync(Request request)
{
TaskCompletionSource<Response> taskCompletionSource =
AsyncServiceClientHelpers.CreateSource<Response>(request);
ProcessRequestCompletedEventHandler handler = null;
handler =
(sender, e) =>
AsyncServiceClientHelpers.TransferCompletion(
taskCompletionSource,
e,
() => e.Result,
() => this.Service.ProcessRequestCompleted -= handler);
this.Service.ProcessRequestCompleted += handler;
try
{
this.Service.ProcessRequestAsync(request, taskCompletionSource);
}
catch (Exception)
{
this.Service.ProcessRequestCompleted -= handler;
taskCompletionSource.TrySetCanceled();
throw;
}
return taskCompletionSource.Task;
}
//Usage:
public async Task<Response> UpdateRequest(some arguments)
{
//Validate arguments and create a Request object
var response = await this.ProcessExtRequestAsync(request)
.ConfigureAwait(false);
return response;
}
}
B 类是以同步的方式使用 ExtSvc
public class B
{
public ExtSvc service {get; set;}
public Response Update(arguments)
{
//some logic
var result = this.ExtSvc.UpdateRequest(arguments).Result;
//some logic
return result
}
}
最后是 MVC 动作(也是同步)
public ActionResult GetResponse(int id)
{
//some logic
B.Update(id);
//some logic
return View(...);
}
描述的流程抛出错误
“System.InvalidOperationException”类型的第一次机会异常 发生在 System.Web.dll
附加信息:异步操作无法在 这次。异步操作只能在一个 异步处理程序或模块或在页面中的某些事件期间 生命周期。如果在执行页面时发生此异常,请确保 该页面被标记为 。这个例外可能 还表示尝试调用“async void”方法,即 在 ASP.NET 请求处理中通常不受支持。相反, 异步方法应该返回一个Task,调用者应该等待 它。
在 ExtSvc 的以下行:this.Service.ProcessRequestAsync(request, taskCompletionSource); ProcessRequestAsync 是一个 void 方法
所以它对应于:
这个例外可能 还表示尝试调用“async void”方法,即 在 ASP.NET 请求处理中通常不受支持
我知道将 GetResponse MVC 操作转换为异步(通过使用 async/await)并将实际使用 ExtSvc 的 B 类转换为异步可以解决问题。
但我的问题是:
如果我不能更改 B 类的签名(因为它实现了一个接口)以返回 Task<Response> 而不是 Response 这基本上意味着我不能在它上面使用 async/await 那么这个问题如何能解决吗?
【问题讨论】:
-
您不能更改 B 类的签名(因为它实现了一个接口),但是您可以让它实现一个带有
Task<T>签名的新接口,并使用那个来代替吗?否则,您将陷入阻塞同步调用;在 ASP.NET 中使用Task.Run包装它们没有意义。 -
@Alex This SO post 可以为您提供更多细节。
标签: c# asp.net-mvc web-services asynchronous async-await