【发布时间】:2021-03-10 19:26:05
【问题描述】:
我有一个 API,可以为我提供一些传感器的状态(位于 Azure 函数中)
www.myapp.com/api/sensors/{sensor_id}
我的客户端应用程序需要每隔一秒检查一次每个传感器!所以在这种情况下,我有 10 个传感器,客户端需要每秒发送 10 个 http get 请求!
我决定使用 Parallel 并从我的方法的每个实例中创建一个池,该实例运行并执行 Get 请求!
这是编排每个传感器并将其添加到池中并全部调用它们的主要方法
public override Task Run(List<int> sensors)
{
try
{
List<Action> actions = new List<Action>();
foreach (var prd in sensors)
{
actions.Add(async () => await Process(prd));
}
ParallelOptions parallelOptions = new ParallelOptions
{
MaxDegreeOfParallelism = 20
};
Parallel.Invoke(parallelOptions, actions.ToArray());
}
catch (Exception ex)
{
Run(sensors);
}
return Task.CompletedTask;
}
在 Process() 方法中,我获取传感器 ID 并将其添加到 API 端点,然后每 1 秒运行一次 Get 请求。
private async Task<string> Process(int sensorId)
{
while (true)
{
Thread.Sleep(1000);
try
{
SensorModel response = _httpClientService.GetAsync<SensorModel>(string.Format(apiUrl, sensorId)).Result;
if (response != null)
{
if (response.Status == "success")
{
.
.
.
}
_logger.LogError($"API connection unsuccesful...");
return null;
}
_logger.LogError($"API connection failed...");
return null;
}
catch (Exception ex)
{
_logger.LogError($"Exception in retrieving sensor data {StringExtensions.GetCurrentMethod()} {ex}");
return null;
}
}
}
和我的 HttpClient 工厂中的 GetAsync
public async Task<T> GetAsync<T>(string uri)
{
string responseData = null;
try
{
var response = await _client.GetAsync(uri);
responseData = await response.Content.ReadAsStringAsync();
if (!string.IsNullOrEmpty(responseData) && response.StatusCode == HttpStatusCode.OK)
return JsonConvert.DeserializeObject<T>(responseData);
return default;
}
catch (Exception ex)
{
_logger.LogError(ex, responseData);
return default;
}
}
现在上面的代码大部分时间都可以正常工作,但有时它只是开始连接失败并返回下面的异常,我可以修复它的唯一方法是重新启动应用程序。不确定它可能会与大量请求以及它们同时处理的事实混淆
System.ArgumentNullException: Value cannot be null. (Parameter 'obj')
at System.OrdinalIgnoreCaseComparer.GetHashCode(String obj)
at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
at System.Net.Http.Headers.HttpHeaders.AddHeaders(HttpHeaders sourceHeaders)
at System.Net.Http.Headers.HttpRequestHeaders.AddHeaders(HttpHeaders sourceHeaders)
at System.Net.Http.HttpClient.SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.GetAsync(String requestUri)
at SensorMonitor.Services.Implementations.HttpClientService.GetAsync[T](String uri)
我知道它在我的 GetAsync 方法中,但不知道为什么它在运行几分钟后发生,而不仅仅是从一开始!
还请注意,我必须通过调用 .Result 来使我的 GetAsync 方法不异步,就好像我确实等待然后应用程序在启动第一个请求之前崩溃!它似乎不喜欢在并行池中被调用。
感谢您的帮助!
更新了更多细节:
HttpClientService.cs
public class HttpClientService : IHttpClientService
{
private readonly HttpClient _client;
private readonly ILogger<HttpClientService> _logger;
private static readonly JsonSerializerSettings JsonSerializerSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
public HttpClientService(HttpClient client, ILogger<HttpClientService> logger)
{
_client = client;
_logger = logger;
}
.
.
.
这就是我注册 HttpClient 的方式
services.AddHttpClient<IHttpClientService, HttpClientService>();
【问题讨论】:
-
如何将 HttpClient 注入到您的 HttpClientService 中?以及如何将您的服务添加到 DI?请更新您的问题
-
完成,谢谢@SaeedEsmaeelinejad
-
不要使用
Thread.Sleep(1000);,而是使用await Task.Delay(1000);并对其进行测试 -
好的,马上试试
-
没用,它经历了一个循环然后就存在了,我认为这是因为在延迟之后它返回一个 Task 并且当 Run 方法得到一个 Task 时,它假定应用程序已完成执行!
标签: c# console-application httpclient .net-5