我有一个程序,它进行web API调用并返回JSON响应。从该JSON响应中,我需要获得Self
链接,并对该端点进行另一次调用,然后自动返回该JSON响应。
在我最初的请求之后,我可能需要重复这个过程2-3次才能到达我想要的最终终点。
来自第一个API调用的JSON响应
public void makeRequestCall()
{
//Making call with base API plus desired endpoint parameters
string url = Consts.getURL;
//iniatialize HttpClient, set credentials, and make call
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(Consts.getURL);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes(Consts.Username + ":" + Consts.Password)));
HttpResponseMessage response = client.GetAsync(url).Result;
// Get the response and print it
if (response.IsSuccessStatusCode)
{
var callResult = response.Content.ReadAsStringAsync().Result;
//deserialize the JSON response
callResult = JsonConvert.DeserializeObject(callResult).ToString();
JObject jObject = JObject.Parse(callResult);
Console.WriteLine(callResult);
}
else
{
Console.WriteLine(response.StatusCode);
}
//...
}
您可以使用一些包装来完成API请求。但让我们从头开始。
使用HttpClient
的服务
class MyService
{
private readonly ILogger _logger;
private readonly string _username = "";
private readonly string _password = "";
private readonly HttpClient _client;
public MyService(HttpClient client, ILogger<MyService> logger)
{
_client = client;
_logger = logger;
// Setup your credentials & headers.
// Do not store _password in plain text its just for demo purpose!
//
_client.DefaultRequestHeaders.Accept.Clear();
_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes(_username + ":" + _password)));
}
public async Task MakeRequestCallsAsync()
{
// Do your first request. In this case to a dummy API
//
var request1 = await ExecuteNextRequestAsync<object, ResponseObject>(null!, (input) =>
{
return "https://dummyjson.com/products";
});
// Do your second request with the result of your first one
//
var request2 = await ExecuteNextRequestAsync<ResponseObject, ResponseProduct>(request1, (input) =>
{
return "https://dummyjson.com/products/" + input.Products.ElementAt(0).Id;
});
// And so on just by using the response of a previous request...
//
}
private async Task<TOut> ExecuteNextRequestAsync<TIn, TOut>(TIn lastResponse, Func<TIn, string> factory)
{
var url = factory(lastResponse);
var response = await _client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var responseJson = await response.Content.ReadAsStringAsync();
_logger.LogInformation($"{responseJson}");
var responseObj = JsonSerializer.Deserialize<TOut>(responseJson);
return responseObj;
}
else
{
_logger.LogError($"{response.StatusCode}");
return default;
}
}
}
注册您的服务
此示例使用Microsoft.Extensions.Http.Polly
为每个服务实现注册一个HttpClient
文档
// In your `Startup.cs` or if you are using > NET 6 in your `Program.cs`
services.AddHttpClient<MyService>()
.SetHandlerLifetime(TimeSpan.FromMinutes(5))
.AddPolicyHandler(GetRetryPolicy());
services.AddScoped<MyService>();
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
}
重要信息:
MyService
基于响应对象调用API,该响应对象可以手动设置,也可以从上一次调用的反序列化响应中使用。但是它总是使用相同的Authorization
-报头。
在中可以找到一个工作的dotnetfiddle示例