I have working code that uses the ExecuteAsync()
method on a Polly policy (IAsyncPolicy<HttpResponseMessage>
) to pull data from a web page. I'd like to add some debug logging to it, but so far I am not able to figure out the correct syntax to have this happen unless I wrap both the logging and http call in a separate method, and then call that via ExecuteAsync
.
This doesn't seem "right" to me, and I feel there is a cleaner or more direct way. I think my issue is that I don't have a complete enough understanding of how Func<T>
and lambda expressions truly operate to pull this off, as when I wrap things in {}
I get errors like:
Not all code paths return a value in lambda expression of type
Func<CancellationToken, Task<HttpResponseMessage>>
.
This is my original working code:
var httpClient = _httpClientFactory.CreateClient();
HttpResponseMessage result;
var retryPolicy = (IAsyncPolicy<HttpResponseMessage>)_policyRegistry[RetryPolicyKeyName];
result = await retryPolicy.ExecuteAsync(
async cancellationToken =>
await httpClient.GetAsync(myUrl, cancellationToken)
, cancellationToken
);
This code produces the "Not all code paths return a value in lambda expression of type Func<CancellationToken, Task>
error:
var httpClient = _httpClientFactory.CreateClient();
HttpResponseMessage result;
var retryPolicy = (IAsyncPolicy<HttpResponseMessage>)_policyRegistry[RetryPolicyKeyName];
result = await retryPolicy.ExecuteAsync(
async cancellationToken =>
{
await httpClient.GetAsync(myUrl, cancellationToken);
}
, cancellationToken
);
This is my "hack" that gets done what I want with an extra method:
private async Task<HttpResponseMessage> TestWithLogAsync(HttpClient httpClient, string myUrl, CancellationToken cancellationToken)
{
_logger.LogDebug("Requesting from: {myUrl}", myUrl);
var result = await httpClient.GetAsync(myUrl, cancellationToken);
return result;
}
var httpClient = _httpClientFactory.CreateClient();
HttpResponseMessage result;
var retryPolicy = (IAsyncPolicy<HttpResponseMessage>)_policyRegistry[RetryPolicyKeyName];
result = await retryPolicy.ExecuteAsync(
async cancellationToken =>
await TestWithLogAsync(httpClient, myUrl, cancellationToken)
, cancellationToken
);
What you have here:
result = await retryPolicy.ExecuteAsync(
await httpClient.GetAsync(managementUrl, cancellationToken)
, cancellationToken
);
Is equivalent to:
result = await retryPolicy.ExecuteAsync(async () => {
return await httpClient.GetAsync(managementUrl, cancellationToken);
}
, cancellationToken
);
Hence this will execute more than one line in the lambda:
result = await retryPolicy.ExecuteAsync(async () => {
_logger.LogDebug("Requesting from: {managementUrl}", managementUrl);
return await httpClient.GetAsync(managementUrl, cancellationToken);
}
, cancellationToken
);
..though I wasn't quite clear on how managementUrl
morphed into myUrl
across your examples, and whether they differ.. I've assumed not