Как изменить ioptions во время выполнения?C#

Место общения программистов C#
Ответить
Anonymous
 Как изменить ioptions во время выполнения?

Сообщение Anonymous »

Я храню информацию о своих услугах (хост, имя) в приложениях. Иногда я хочу получить информацию о хосте не от приложений, а из консула. Поэтому я хочу настроить ioptions во время выполнения, проверьте, представлен ли хост, и если я хочу запросить консул, чтобы получить его. > Посмотрите на это: < /p>

Код: Выделить всё

"MyServices": {
"MyServiceA": {
"ServiceName": "ServiceAName",
"ConsulDataCenter": "",
"Host": "http://localhost:12345"
},
"MyServiceB": {
"ServiceName": "ServiceBName",
"ConsulDataCenter": ""
}
}
Таким образом, Servicea хост должен быть взят из AppSettings и ServiceB хост должен быть взят из консула.
Во -первых, я Создал класс, представляющий мои параметры: < /p>

Код: Выделить всё

public class MyServicesOptions : Dictionary { }

public sealed class ConsulServiceData
{
public required string ServiceName { get; init; }
public required string ConsulDataCenter { get; init; }
public string Host { get => _uri?.Host; set => _uri = new Uri(value); }
public Uri Uri { get => _uri; }
private Uri _uri;
}
Далее мне нужно настроить ioptions . Я создал интерфейс: < /p>

Код: Выделить всё

public interface IConfigureOptionsAsync where TOptions : class
{
Task ConfigureAsync(TOptions options, CancellationToken cancellationToken = default);
}
< /code>
и класс, который реализует вышеуказанную логику конфигурации: < /p>
 public class ConfigureServicesAsync : IConfigureOptionsAsync
{
protected readonly ConsulService _consulService;
private readonly ILogger _logger;

public ConfigureMyServicesAsync(ConsulService consulService, ILogger logger)
{
_consulService = consulService;
_logger = logger;
}

public virtual async Task ConfigureAsync(MyServicesOptions options, CancellationToken cancellationToken = default)
{
try
{
foreach (var (clientName, client) in options)
{
if (string.IsNullOrEmpty(client.Host))
{
var result = await _consulService.GetServiceUriAsync(client.ServiceName, null, new QueryOptions { Datacenter = client.ConsulDataCenter }, cancellationToken).ConfigureAwait(false);
if (result is null)
{
_logger.LogWarning("Could not retrieve address from consul for service {serviceName}.  Reason: {error}", client.ServiceName, result.Error);
continue;
}
client.Host = result;
}
_logger.LogInformation("Address for {serviceName} - {uri}", client.ServiceName, client.Uri);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error while configuring rest consul services: {exception}", ex.Message);
throw;
}
}
}
< /code>
Затем создайте размещенную службу для асинхронной конфигурации: < /p>
public class ConfigureOptionsHostedService : IHostedService where TOptions : class
{
private readonly IServiceProvider _services;

public ConfigureOptionsHostedService(IServiceProvider services)
{
_services = services;
}

public async Task StartAsync(CancellationToken cancellationToken)
{
using var scope = _services.CreateScope();
var configurator = scope.ServiceProvider.GetRequiredService();
var options = scope.ServiceProvider.GetRequiredService();
await configurator.ConfigureAsync(options.CurrentValue, cancellationToken);
}

public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
< /code>
Создать методы для размещенной службы для конфигурации параметров < /p>
public static IServiceCollection ConfigureOptionsAsync(this IServiceCollection services)
where TConfigureOptionsAsync : class, IConfigureOptionsAsync
where TOptions : class
{
services.AddHostedService();
services.AddScoped();
return services;
}
< /code>
и зарегистрировать все вещи < /p>
public static void AddMyServices(this IServiceCollection services, IConfiguration configuration)
{
services.Configure(configuration.GetSection("MyServices"));
services.ConfigureOptionsAsync();
}
Наконец, я хочу получить адрес для моего httpclient от ioptions .

Код: Выделить всё

 services.AddHttpClient((sp, client) =>
{
var uri = sp.GetRequiredService().Value.GetValueOrDefault("ServiceA")?.Uri;

client.BaseAddress = uri;
});

services.AddHttpClient((sp, client) =>
{
var uri = sp.GetRequiredService().Value.GetValueOrDefault("ServiceB")?.Uri;

client.BaseAddress = uri;
});
< /code>
И вот вопрос. Httpclient 
для Servicea , который был указан в appsettings.json , получается правильно. Но ServiceB Адрес null . Я думал, что запрос на консул возвращает null (строка от configureservicesasync )

Код: Выделить всё

var result = await _consulService.GetServiceUriAsync(client.ServiceName, null, new QueryOptions { Datacenter = client.ConsulDataCenter }, cancellationToken).ConfigureAwait(false);
Но это не так, адрес правильно получен из консула и назначает его на хост в параметрах.
Так что же у меня Я делаю не так? Почему моя конфигурация ioptions не работает, даже если я получаю правильный адрес от консула и назначаю его правильно?

Подробнее здесь: https://stackoverflow.com/questions/776 ... ng-runtime
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»