我正在重构执行同步http请求的旧代码,并返回带有成功和失败事件的Callback对象。如何正确地将代码包装到async / await中?
我已经添加了HttpClient类,我正在使用我等待的SendAsync方法,但我不确定如何正确地从await转换为事件。我在类中添加了异步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());
看起来它有点火和忘记,但有回调(我等待网络的响应)。如何妥善处理?
我正在重构执行同步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);
}