我正在编写一个 Webapi,当第一个 HTTP 端点失败时,我必须调用 HTTP 的第二个端点。但是,对于第二个 HTTP 调用,我的应用程序不应该阻塞主线程并且应该返回不成功的结果。我的 HTTP 客户端已经配备了 Polly 重试策略,重试后,我想在不阻塞主线程的情况下静默调用第二个 URL。我的代码如下所示。
public class Request
{
public string Id { get; set; }
}
public class Result
{
public string Id { get; set; }
public bool IsSuccess { get; set; }
public string Message { get; set; }
}
public class Service
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly Ilogger _appLogger;
private readonly string _url1="www.somedomain.com/api1";
private readonly string _url2="www.somedomain.com/api2";
Service(IHttpClientFactory factory,Ilogger logger)
{
_httpClientFactory = httpClientFactory;
_appLogger = logger;
}
public async Task<Result> Send(Request request)
{
try
{
using var client = _httpClientFactory.CreateClient();
using HttpRequestMessage httpRequest =new HttpRequestMessage(HttpMethod.Post, _url1);
var req = JsonConvert.SerializeObject<Request>(body);
var stringContent = new StringContent(req, Encoding.UTF8, "json");
var result = await client.SendAsync(httpRequest);
var resultContent = await result.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<Result>(resultContent));
}
catch (Exception ex)
{
if (ex is OperationCanceledException || ex is TaskCanceledException)
{
//Second call needed but don't want to hold the result
// Task.Run(async ()=> await Log(request)) //Approach 1
// Task.Factory.StartNew(async () => await Log(request)) //Approach 2
// HostingEnvironment.QueueBackgroundWorkItem(ct => Log(request).ConfigureAwait(false)); //Approach 3
// QueuedHostedService defined here [Microsoft][1]
// var jobId = BackgroundJob.Enqueue(() => Log(request).ConfigureAwait(false)); //Approach 4 by hangfire [Hangfire][2]
// Custome singleton suggested here // [CustomImplementation][1]
}
//No 2nd call needed
await _appLogger.LogAsync(new ExceptionLog(ex));
return Result{IsSuccess=false;};
}
}
public async Task Log(Request request)
{
try
{
using var client = _httpClientFactory.CreateClient();
using var httpRequest =new HttpRequestMessage(HttpMethod.Post, _url2);
var req = JsonConvert.SerializeObject<Request>(body);
var stringContent = new StringContent(req, Encoding.UTF8, "json");
var result = await client.SendAsync(httpRequest);
var resultContent = await result.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<Result>(resultContent));
await _appLogger.LogAsync("2nd call successful.",result );
}
catch (Exception ex)
{
await _appLogger.LogAsync("2nd call failed",ex);
}
}
}
我一直在寻找许多解决方案,但现在对它们感到困惑。[1] : https ://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-6.0&tabs=visual-studio [2]:https://www. hangfire.io/ [3]:https ://anduin.aiursoft.com/post/2020/10/14/fire-and-forget-in-aspnet-core-with-dependency-alive