![](/img/trans.png)
[英]Why does using using RestClient.ExecuteAsync with await fail silently when RestClient.Execute works?
[英]In C#, using a loan pattern, TryAsync, and RestClient.ExecuteAsync(), how can I get the system to wait for the result of the second callout?
我目前正在重構一個使用 RestSharp 的RestClient
調用 Personio 的微服務,以便使用最新版本的 RestSharp (v107),以及使用ExecuteAsync
而不是Execute
。
我有以下方法:
[SuppressMessage("Style", "IDE0053:Use expression body for lambda expressions", Justification = "lambda leave Match ambiguous.")]
public TryAsync<T> WithAuthorization<T>(Func<Token, Task<T>> doSomething, CancellationToken cancellationToken) =>
TryAsync(async () =>
{
T? result = default;
Exception? resultException = null;
TryAsync<Token> authorizationAttempt = TryAuthorize(cancellationToken);
_ = await apply(token => doSomething(token), authorizationAttempt)
.Match(
Succ: async dataTask =>
{
result = await dataTask;
},
Fail: exception =>
{
resultException = exception;
}
)
.ConfigureAwait(false);
// FIXME: Does not wait!!!!
return result
?? ((resultException == null)
? throw new PersonioRequestException("Could not get data from Personio: Reason unknown.")
: throw new PersonioRequestException($"Could not get data from Personio: {resultException.Message}", resultException)
);
});
如上面的代碼所示,該方法在返回結果之前不會等待,或者碰巧拋出原因未知的異常。
使用調試器,我已經能夠確定authorizationAttempt
獲得了一個值並調用了doSomething()
,但是在等待響應時,拋出了錯誤。
使用上述方法的代碼,為doSomething()
提供 function 是這樣的:
public TryAsync<RequestResponse<T>> TryGet<T>(RequestOptions options, CancellationToken cancellationToken) =>
_authorizationClient.WithAuthorization<RequestResponse<T>>(
async token =>
{
UriBuilder urlBuilder = new(_personioConfig.BaseUrl.AppendPathSegment(options.Endpoint))
{
// This is used to add parameters which are used for filtering and may be unique for the record type, such as "updated_from".
Query = options.QueryParameters.ToString()
};
RestRequest request = new(urlBuilder.Uri, Method.Get);
request.Timeout = -1;
if (options.Pagination.IsActive)
{
request = request.AddQueryParameters(options.Pagination);
}
request = request
.AddHeader("Accept", "application/json")
.AddHeader("Authorization", $"Bearer {token.Value}");
return await GetRecords<T>(request, cancellationToken);
},
cancellationToken
);
private async Task<RequestResponse<T>> GetRecords<T>(RestRequest request, CancellationToken cancellationToken)
{
RestResponse<RequestResponse<T>> requestResponse = await _restClient.ExecuteAsync<RequestResponse<T>>(request, cancellationToken);
// FIXME: The next line is never executed.
RequestResponse<T>? dataResponse = JsonConvert.DeserializeObject<RequestResponse<T>>(requestResponse?.Content ?? "");
return (requestResponse?.IsSuccessful ?? false)
? (dataResponse != null && dataResponse.WasSuccessful)
? dataResponse
: throw new PersonioRequestException("Connected to Personio, but could not get records.")
: throw (
(requestResponse?.ErrorException != null)
? new("Could not get records from Personio.", requestResponse.ErrorException)
: new($"Could not get records from Personio. {dataResponse?.Error?.Message ?? UnknownProblem}."));
}
如上面的代碼所示,方法GetRecords()
被調用,但系統在ExecuteAsync()
有任何結果之前未填充result
(返回上面的第一個方法)引發錯誤。
早期形式的代碼,早期版本的 RestSharp(v106) 和同步執行工作正常。 當時, TryGet
看起來像:
public TryAsync<RequestResponse<T>> TryGet<T>(RequestOptions options) =>
_authorizationClient.WithAuthorization<RequestResponse<T>>(token =>
{
UriBuilder urlBuilder = new(_personioConfig.BaseUrl.AppendPathSegment(options.Endpoint))
{
// This is used to add parameters which are used for filtering and may be unique for the record type, such as "updated_from".
Query = options.QueryParameters.ToString()
};
_restClient.BaseUrl = urlBuilder.Uri;
_restClient.Timeout = -1;
IRestRequest request = new RestRequest(Method.GET);
if (options.Pagination.IsActive)
{
request = request.AddQueryParameters(options.Pagination);
}
request = request
.AddHeader("Accept", "application/json")
.AddHeader("Authorization", $"Bearer {token.Value}");
return Task.FromResult(GetRecords<T>(request));
});
private RequestResponse<T> GetRecords<T>(IRestRequest request)
{
IRestResponse<RequestResponse<T>> requestResponse = _restClient.Execute<RequestResponse<T>>(request);
RequestResponse<T>? dataResponse = JsonConvert.DeserializeObject<RequestResponse<T>>(requestResponse.Content);
return requestResponse.IsSuccessful
? (dataResponse != null && dataResponse.WasSuccessful)
? dataResponse
: throw new PersonioRequestException("Connected to Personio, but could not get records.")
: throw (
(requestResponse.ErrorException != null)
? new("Could not get records from Personio.", requestResponse.ErrorException)
: new($"Could not get records from Personio. {dataResponse?.Error?.Message ?? UnknownProblem}."));
}
我做錯了什么或錯過了什么? 如何使用 RestSharp 107.x 和ExecuteAsync()
完成這項工作?
感謝@AlexeyZimarev,我能夠讓 TryGet() 方法工作。
現在看起來像:
public TryAsync<RequestResponse<T>> TryGet<T>(RequestOptions options, CancellationToken cancellationToken) =>
TryAsync(async () =>
{
_restClient.Authenticator = _authorizationClient;
Uri uri = new UriBuilder(_personioConfig.BaseUrl.AppendPathSegment(options.Endpoint)).Uri;
RestRequest request = new RestRequest(uri, Method.Get)
.AddQueryParameters(options.QueryParameters);
if (options.Pagination.IsActive)
{
request = request.AddQueryParameters(options.Pagination);
}
request.Timeout = -1;
return await GetRecords<T>(request, cancellationToken);
});
_restClient.Authenticator = _authorizationClient;
這里不是很安全,因為它被分配在注入而不是 RestClient 上,將來可能會在其他地方使用,但我通過使客戶端瞬態而不是 singleton “解決”了這個問題。
我還從PersonioAuthorizationClient
中刪除了所有 TryAsync,因為無論AuthenticatorBase
正在做什么,它似乎都不能很好地發揮作用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.