我正在重构执行同步http请求并返回带有成功和失败事件的Callback对象的旧代码。如何将代码正确包装到async / await中?
我添加了HttpClient类,并且正在使用我等待的SendAsync方法,但是我不确定如何正确地进行从等待到事件的转换。我在类中添加了异步void Execute方法,但它似乎不是正确的处理方式-避免异步void。下面是(简短版本的)代码中的更多说明。
public class HttpExecutor(){
public event Action<string> Succeed;
public event Action<ErrorType, string> Failed;
private bool isExecuting;
//I know that async void is not the best because of exceptions
//and code smell when it is not event handler
public async void Execute()
{
if (isExecuting) return;
isExecuting = true;
cancellationTokenSource = new CancellationTokenSource();
try
{
httpResponseMessage =
await httpService.SendAsync(requestData, cancellationTokenSource.Token).ConfigureAwait(false);
var responseString = string.Empty;
if (httpResponseMessage.Content != null)
{
responseString = await httpResponseMessage.Content.ReadAsStringAsync().ConfigureAwait(false);
}
if (httpResponseMessage.IsSuccessStatusCode)
{
Succeed?.Invoke(responseString);
return;
}
Failed?.Invoke(httpResponseMessage.GetErrorType(),
$"{httpResponseMessage.ReasonPhrase}\n{responseString}");
}
//Catch all exceptions separately
catch(...){
}
finally
{
Dispose();
}
}
}
public class UserService(){
public CallbackObject<User> GetUser(){
var executor = new HttpExecutor(new RequestData());
//CallbackObject has also success and fail, and it hooks to executor events, deserializes string into object and sends model by his own events.
var callback = new CallbackObject<User>(executor);
executor.Execute();//in normal case called when all code has possibility to hook into event
return callback;
}
}
我觉得我应该将方法更改为:public async Task ExecuteAsync(){...}
,但随后我需要通过执行Task.Run(()=>executor.ExecuteAsync());
似乎有点忘了,但是有回调(我正在等待网络的响应)。如何正确处理呢?
答案 0 :(得分:2)
我正在重构执行同步http请求并返回带有成功和失败事件的Callback对象的旧代码。如何将代码正确包装到async / await中?
您完全摆脱了回调。
首先,考虑故障情况。 (ErrorType, string)
应设为自定义Exception
:
public sealed class ErrorTypeException : Exception
{
public ErrorType ErrorType { get; set; }
...
}
然后,您可以将Succeed
/ Failed
回调建模为单个Task<string>
:
public async Task<string> ExecuteAsync()
{
if (isExecuting) return;
isExecuting = true;
cancellationTokenSource = new CancellationTokenSource();
try
{
httpResponseMessage = await httpService.SendAsync(requestData, cancellationTokenSource.Token).ConfigureAwait(false);
var responseString = string.Empty;
if (httpResponseMessage.Content != null)
{
responseString = await httpResponseMessage.Content.ReadAsStringAsync().ConfigureAwait(false);
}
if (httpResponseMessage.IsSuccessStatusCode)
return responseString;
throw new ErrorTypeException(httpResponseMessage.GetErrorType(),
$"{httpResponseMessage.ReasonPhrase}\n{responseString}");
}
catch(...){
throw ...
}
finally
{
Dispose();
}
}
用法:
public Task<User> GetUserAsync()
{
var executor = new HttpExecutor(new RequestData());
var text = await executor.ExecuteAsync();
return ParseUser(text);
}