Как сослаться на размещенную службу в .Net Core 3?

Еще в .net core 2 я создал размещенную службу с пользовательским свойством, например:

 public class MyService : BackgroundService 
{
public bool IsRunning {get;set;}
...

Что я мог бы настроить в startup.cs, например:

public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IHostedService,HostedServices.MyService>();
...

И тогда я мог бы сослаться на него в другом месте на странице бритвы, например:

public class IndexModel : PageModel
{
    private readonly IHostedService _mySrv;
    public IndexModel(IHostedService mySrv) => _mySrv = mySrv;

    [BindProperty]
    public bool IsRunning { get; set; }

    public void OnGet() => IsRunning = ((HostedServices.MyService)_mySrv).IsRunning;
}

Теперь, когда я обновился до .net core 3, мой запуск изменился на:

services.AddHostedService<HostedServices.MyService>();

Но моя ссылка на DI в IndexModel больше не дает мне мой MyService, вместо этого он дает мне объект типа GenericWebHostService, из которого я не могу понять, как получить свой собственный MyService. Изменение «IHostedService» на «MyService» в IndexModel также не работает, я получаю сообщение об ошибке «Невозможно разрешить службу».

Как вернуть экземпляр MyService из инъекции зависимостей?


person Phil    schedule 27.10.2019    source источник


Ответы (1)


В версии 2.2 установка, с которой вы сработали, в основном случайно. Всякий раз, когда вы регистрируете несколько реализаций для службы, «выигрывает» последняя зарегистрированная. Например, возьмите следующий код:

services.AddSingleton<IHostedService, HostedService1>();
services.AddSingleton<IHostedService, HostedService2>();

// ...

public IndexModel(IHostedServie hostedService) { }

Реализация IHostedService, которая внедряется в IndexModel, называется HostedService2; последний зарегистрированный. Если бы IndexModel нужно было обновить, чтобы принять IEnumerable<IHostedService>, он получил бы обе реализации в порядке регистрации:

public IndexModel(IEnumerable<IHostedService> hostedServices) { }

Когда я сказал "случайно", я имел в виду, что в вашем примере регистрируется только HostedServices.MyService, поэтому он также регистрируется последним и, следовательно, "выигрывает".

В версии 3.0 при использовании Generic Host, реализация IHostedService, GenericWebHostService, обрабатывает веб-запросы. Это создает проблему, поскольку GenericWebHostService регистрируется после HostedServices.MyService. Надеюсь, к настоящему моменту стало ясно, что именно по этой причине IHostedService, который вы запрашиваете в IndexModel, не соответствует вашим ожиданиям.

Что касается решения, я предлагаю выполнить две регистрации:

services.AddSingleton<HostedServices.MyService>();
services.AddHostedService(sp => sp.GetRequiredService<HostedServices.MyService>());

Затем обновите свой IndexModel, чтобы он требовал вашей конкретной реализации:

public IndexModel(HostedServices.MyService myService) { }

Это позволяет вам ориентироваться на вашу конкретную реализацию IHostedService. Он регистрируется дважды для двух разных типов служб, но создается только один экземпляр.

person Kirk Larkin    schedule 27.10.2019
comment
@KirkLarkin правда подожди? Где я могу найти доказательства этого, потому что я не понимаю, что вызовет StartAsync и StopAsync в сервисе, если вы просто добавите его как синглтон. Также этот ответ кажется противоречащим вашим утверждениям. - person Joelius; 27.10.2019
comment
@Joelius Пока он зарегистрирован за интерфейсом IHostedService, он работает нормально. На самом деле это все, что делает AddHostedService. Я найду ссылку на исходный код, чтобы доказать это... - person Kirk Larkin; 27.10.2019
comment
@Joelius Вот вам идти. Host просто запрашивает IEnumerable<IHostedService> и вызывает StartAsync их всех. Ответ, который вы связали, просто говорит AddSingleton без указания того, что интерфейс не работает, и это правильно. Я не говорю иначе. Это вторая регистрация, которую я показал, которая связывает их вместе. - person Kirk Larkin; 27.10.2019
comment
О, это то, что стоит знать. Это упоминается в документах? Я чувствую, что легко предположить, что он может не делать то же самое (хотя это разумно, что он делает). - person Joelius; 27.10.2019