Доступ к элементам словаря в методе Override - PullRequest
0 голосов
/ 23 сентября 2019

У меня есть класс ниже в webapi, который добавляет в словарь, однако каждый раз, когда вызывается метод checkstatus (с помощью Task.Delay), он говорит, что словарь пуст.Это потому, что он работает в другом потоке?Должен ли я использовать конкурентный вместо этого?

internal class Sms : smsBase
{
    private const int CheckFrequencyMilliseconds = 1000;
    private Dictionary<CustomerDetails, decimal> _registeredCustomers;

    public Sms(ILogger<Sms> logger)
        : base(TimeSpan.FromMilliseconds(CheckFrequencyMilliseconds), logger)
    {
        _registeredCustomers = new Dictionary<CustomerDetails, decimal>();
    }

    protected override Task CheckStatus()
    {

        foreach (var rc in _registeredCustomers)
        {
         //do something
        }

        return Task.CompletedTask;
    }

    public Task RegisterCustomer(CustomerDetails customer)
    {
        _registeredCustomers.Add(customer, 1);
        return Task.CompletedTask;
    }
}

Код базового класса ниже.

public abstract class smsBase : BackgroundService
{
    private readonly TimeSpan _tickFrequency;
    private readonly ILogger<smsBase> _logger;

/// <inheritdoc />
/// <param name="tickFrequency">Frequency that the service will execute the CheckStatus method.</param>
protected smsBase (TimeSpan tickFrequency,ILogger<smsBase> logger)
{
  this._tickFrequency = tickFrequency;
  this._logger = logger;
}

/// <inheritdoc />
protected override sealed async Task ExecuteAsync(CancellationToken stoppingToken)
{
  this._logger.LogInformation("Service is starting.");
  while (!stoppingToken.IsCancellationRequested)
  {
    ConfiguredTaskAwaitable configuredTaskAwaitable;
    try
    {
      configuredTaskAwaitable = this.CheckStatus().ConfigureAwait(false);
      await configuredTaskAwaitable;
    }
    catch (Exception ex)
    {
      this._logger.LogError(ex, "An exception was thrown whilst checking registered strategies.");
      throw;
    }
    configuredTaskAwaitable = Task.Delay(this._tickFrequency, stoppingToken).ConfigureAwait(false);
    await configuredTaskAwaitable;
  }
  this._logger.LogInformation("Service is stopping.");

protected abstract Task CheckStatus();
}

И ниже - запуск cs

    public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services
            .AddSwaggerGen(options => {
                options.SwaggerDoc("v1", new Info() { Title = "Customers.WebApi", Version = "v1" });
            })
            .AddMvc(options => {
                options.Filters.Add(new ExceptionFilter());
                options.Filters.Add(new ProducesAttribute("application/json"));
            })
            .AddJsonOptions(options => {
                options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
                options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            });

        services.AddHostedService<Sms>();
        services.AddSingleton<ISms, Sms>();
    }

1 Ответ

2 голосов
/ 23 сентября 2019

В вашем вопросе пропущено много моментов, но я полагаю, что я могу вывести проблему только из этих 2 строк

services.AddHostedService<Sms>();
services.AddSingleton<ISms, Sms>();

Строка AddSingleton создаст один экземпляр Sms для вашегоприложение, и я подозреваю, что вы вводите ISms в контроллер где-то и вызываете RegisterCustomer.

Строка AddHostedService создаст второй экземпляр Sms и будет использовать его в качестве размещенной службы.

Решение состоит в том, чтобы разделить эти две вещи, иесть что-то вроде ICustomerRepository, которое совместно используется как размещенной службой, так и контроллерами.


Обратите внимание, что если я не в курсе, это поможет отредактировать ваш вопрос с подробной информацией оISms, включая то, как он используется и куда вы звоните RegisterCustomer.

...