Базовый хост ASP.NET Core (HostBuilder) Не удается разрешить службу для типа ... при попытке активации - PullRequest
0 голосов
/ 12 октября 2018

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

Сбой во время выполнения с приведенным ниже исключением.Я прочитал десятки постов, касающихся WebHostBuilder, но не могу связать обсуждения с тем, что я пытаюсь сделать с HostBuilder.Я явно упускаю что-то фундаментальное и буду очень признателен за руль.Придуманный пример кода приведен ниже.PS Я верю, что выполнил подходящую работу по форматированию и маркировке, чтобы успокоить тех, кто действительно знает, что они делают - очевидно, я не знаю!

Исключение

Система.InvalidOperationException: «Не удается разрешить службу для типа« MyNoobProject.IToDo »при попытке активировать« MyNoobProject.DoSomethingWithToDo ». '

Program.cs

using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

public static async Task Main(string[] args)
    {
        var builder = new HostBuilder()
            .ConfigureServices((hostContext, services) =>
            {
                services.AddSingleton<IHostedService, ToDo>();
                services.AddSingleton<IHostedService, DoSomethingWithToDo>();

            })                
            .ConfigureLogging((hostingContext, logging) => {
               logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
                logging.AddConsole();
            });;

        await builder.RunConsoleAsync();
    }

StackOverflow.cs *»1014 *

using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

namespace MyNoobProject
{
interface IToDo
{
    Task Add(int i);
    void Dispose();
}

class ToDo : IHostedService, IDisposable, IToDo
{
    private BlockingCollection<int> _blockingCollection;

    private readonly ILogger _logger;

    public ToDo(ILogger<ToDo>logger)
    {
        _logger = logger;
    }

    public Task Add(int i)
    {
        _blockingCollection.Add(i);
        return Task.CompletedTask;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _blockingCollection = new BlockingCollection<int>();
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _blockingCollection.CompleteAdding();
        return Task.CompletedTask;
    }

    public void Dispose()
    {
        _blockingCollection.Dispose();
    }
}

interface IDoSomethingWithToDo
{

}

class DoSomethingWithToDo : IHostedService, IDisposable, IDoSomethingWithToDo
{
    private IToDo _todo;

    public DoSomethingWithToDo(IToDo todo)
    {
        _todo = todo;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _todo.Add(1);
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }

    public void Dispose()
    {

    }
}
}

1 Ответ

0 голосов
/ 12 октября 2018

Поставщик услуг не может разрешить интерфейс IToDo, так как он не был зарегистрирован в коллекции служб.

Таким образом, вы уже зарегистрировали реализацию ToDo в качестве единственной размещенной службы.

services.AddSingleton<IHostedService, ToDo>();
services.AddSingleton<IHostedService, DoSomethingWithToDo>();

Я бы предложил немного изменить его структуру, если вы хотите использовать интерфейс в конструкторе другого сервиса.

Поскольку у сервиса простой конструктор, вы можете инициализировать его в корне композиции и применитьнеобходимая регистрация

var todo = new ToDo();
services.AddSingleton<IToDo>(todo);
services.AddSingleton<ToDo>(todo);
services.AddSingleton<IHostedService>(todo);
services.AddSingleton<IHostedService, DoSomethingWithToDo>();

Таким образом, интерфейс, введенный в конструктор DoSomethingWithToDo, будет использовать синглтон, определенный при запуске

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

//adding implementation first
services.AddSingleton<ToDo>();
//adding options for interfaces
services.AddSingleton<IToDo>(_ => _.GetService<ToDo>());
services.AddSingleton<IHostedService>(_ => _.GetService<ToDo>());
//...
services.AddSingleton<IHostedService, DoSomethingWithToDo>();
...