Внедрение / дублирование зависимости добавлено как Singleton - PullRequest
1 голос
/ 07 января 2020

Я не могу понять, почему инъекция зависимостей работает не так, как ожидалось, когда мой контроллер получает удар, конструктор MyFirstService снова получает удар, и поэтому я подключаю другой токен отмены к тому, который у меня будет sh быть при вызове метода StopFeeds().

Я пытался добавить контроллер в качестве одиночного и использовать метод контроллера StartFeed() для создания экземпляра класса, но независимо от того, что я делаю с DI (общий ctor DI, явное присвоение свойств, [FromServices] и даже прямая передача в коллекцию сервисов), когда я нажимаю стоп-фиды, создается еще один экземпляр MyFirstService ... Есть идеи?


Интерфейс:

public interface IFirstService : IService
{
    OrderDto CreateOrder(Order order);
    Task<string> ProcessOrder(string orderXml);
    void ProcessLineItems(ref List<NewLineItem> items, ref int lineNum, Item i, string orderId);
    NewOrderEvent NewOrderEvent(OrderDto newOrder, Order order, List<NewLineItem> lineItems);
}

MyFirstService:

public class MyFirstService : IFirstService
{
    private SftpService _sftpService;
    private readonly ITimer<MyService> _timer;
    private readonly IMediator _mediator;
    private readonly ILogger<MyService> _logger;
    private readonly MyFirstConfig _iOptions;

    private CancellationTokenSource CancellationTokenSource;

    public MyService(IMediator mediator, ILogger<MyService> logger, IOptionsSnapshot<MyFirstConfig> iOptions)
    {
        _mediator = mediator;
        _timer = new Timer<MyFirstService>(logger);
        _logger = logger;
        _iOptions = iOptions.Value;

        CancellationTokenSource = new CancellationTokenSource();
        CancellationTokenSource.Token.Register(FeedStopped);
    }

    private void CreateSftpService()
    {
        _sftpService = new SftpService(_iOptions.SftpOptions);
    }

    public void StartFeed()
    {
        CreateSftpService();
        StartFeed(TimerSchedule);
    }

    public void StartFeed(TimeSpan timeSpan)
    {
        _timer.ScheduleCallback(timeSpan, ProcessOrderFeedAsync, CancellationTokenSource.Token);
    }

    public void StopFeed()
    {
        CancellationTokenSource.Cancel();
        _sftpService.Dispose();
    }

Запуск:

services.Configure<MyFirstConfig>(Configuration.GetSection("FirstSection"));
services.Configure<MySecondConfig>(Configuration.GetSection("SecondSection"));

services.AddSingleton<IFirstService, MyFirstService>();
services.AddSingleton<ISecondService, MySecondService>();

var serviceProvider = services.BuildServiceProvider();
serviceProvider.GetRequiredService<IFirstService>().StartFeed();
serviceProvider.GetRequiredService<ISecondService>().StartFeed();

Контроллер: (Я работаю с другими кодами состояния, Я убрал попытку / поймать, поскольку они не имеют значения)

using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Mvc;
using System.Linq;
using System.Threading.Tasks;
using SFTP.Services;
using System;

namespace API.Controllers
{
    [Route("api/[controller]/")]
    [ApiController]
    public class MyController : Controller
    {
        [HttpPost]
        [Route("feeds/start")]
        public IActionResult StartFeed([FromServices] IFirstService myService)
        {
            myService.StartFeed();
            return Ok();
        }

        [HttpPost]
        [Route("feeds/stop")]
        public IActionResult StopFeed([FromServices] IFirstService myService)
        {
            myService.StopFeed();
            return Ok();
        }
    }
}

Ответы [ 2 ]

3 голосов
/ 07 января 2020

Это не предназначено как ответ (следовательно, сообщество вики). Тем не менее, я чувствовал, что это было важно, тем не менее, и было бы невозможно четко объяснить это через комментарий.

Вы не должны внедрять IConfiguration в такой сервис, как этот. Это создает тесную связь между вашей конфигурацией и службой, как методом получения конфигурации (Microsoft.Extensions.Configuration), так и магическими c строками типа MySection. Если формат конфига изменится, ваша служба сломается, потому что это зависит от вещей (как знания о том, что в конфигурации есть раздел MySection, так и от того, как этот конфиг получен), что он на самом деле ничего не должен знать о .

Вместо этого вы всегда должны просто вводить информацию, которая вам действительно необходима, то есть значения Host, Username, Password и т. Д. c. Когда таких токенов много, вы можете вместо этого рассмотреть возможность создания класса параметров для их инкапсуляции, а затем внедрить его вместо этого. Например:

public class SftpServiceOptions
{
    public string Host { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
    ...
}

Затем вы можете даже использовать шаблон параметров, чтобы легко связать значения из вашей конфигурации:

services.Configure<SftpServiceOptions>(Configuration.GetSection("MySection"));

Теперь строка magi c находится в вашем настройка приложения вместо какого-либо случайного сервиса, что делает его более очевидным и более простым для отслеживания, если оно когда-либо изменится.

0 голосов
/ 07 января 2020

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

Я переместил Войдите c в метод Configure() и IApplicationBuilder теперь обрабатывает запуск каналов для создания экземпляра каждой службы:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MyFirstConfig>(Configuration.GetSection("Next"));
    services.Configure<MySecondConfig>(Configuration.GetSection("CustomGateway"));

    services.AddSingleton<IFirstService, MyFirstService>();
    services.AddSingleton<ISecondService, MySecondService>();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    app.ApplicationServices.GetRequiredService<IFirstService>().StartFeed();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...