.Использование заводского шаблона с внедрением зависимостей NET Core 3.1 - PullRequest
1 голос
/ 27 мая 2020

У меня есть API. NET Core 3.1, который может использовать RabbitMq или Azure Service Bus. Выбор будет определяться через параметр конфигурации. Поскольку конфигурация, которую нужно использовать, является решением среды выполнения, я sh буду использовать фабричный шаблон вместе с. NET инъекцией зависимостей ядра. Я нашел статью по адресу https://medium.com/@mailbox.viksharma / factory-pattern-using-built-in-dependency-injection-of- asp - net -core-f91bd3b58665 , но не могу заставить фабрику работать . Любая помощь будет принята с благодарностью.

Проблема возникает в классе Factory из-за IServiceProvider. Я получаю сообщение об ошибке System.NullReferenceException: ссылка на объект не установлена ​​для экземпляра объекта. при попытке GetService.

Factory class

public class MessageServiceFactory
{
    readonly IServiceProvider serviceProvider;

    public MessageServiceFactory(IServiceProvider serviceProvider)
    {
        this.serviceProvider = serviceProvider;
    }

    public IMessagingService GetMessagingService()
    {
        var messageProvider = ConfigProvider.GetConfig("MessageService", "Messaging_Service");

        switch(messageProvider)
        {
            case "AzureServiceBus": return (IMessagingService)serviceProvider.GetService(typeof(MassTransitAzureServiceBusMessagingService));
            case "RabbitMq": return (IMessagingService)serviceProvider.GetService(typeof(MassTransitRabbitMqMessagingService));
                default: throw new ArgumentException("Invalid message service");
        };
    }
}

Сервисный интерфейс

public interface IMessagingService
{
    Task Publish(object payload);
}

Конкретная реализация RabbitMq

public class MassTransitRabbitMqMessagingService : IMessagingService
{
    readonly IMassTransitRabbitMqTransport massTransitTransport;

    public MassTransitRabbitMqMessagingService(IMassTransitRabbitMqTransport massTransitTransport)
    {
        //transport bus config already happens in massTransitTransport constructor
        this.massTransitTransport = massTransitTransport;
    }

    public async Task Publish(object payload)
    {
        ....
    }
}

ConfigureServices в Startup.cs

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton(Configuration);

        services.AddScoped<IMassTransitRabbitMqTransport, MassTransitRabbitMqTransport>();
        services.AddScoped<IMassTransitAzureServiceBusTransport, MassTransitAzureServiceBusTransport>();

        services.AddScoped<MessageServiceFactory>();

        services.AddScoped<IMessagingService, MassTransitAzureServiceBusMessagingService>(s => s.GetService<MassTransitAzureServiceBusMessagingService>());
        services.AddScoped<IMessagingService, MassTransitRabbitMqMessagingService>(s => s.GetService<MassTransitRabbitMqMessagingService>());

        services.AddControllers();
    }

Контроллер

[ApiController]
[Route("api/[controller]")]
public class ListenerController : ControllerBase
{
    readonly ILogger<ListenerController> logger;
    readonly MessageServiceFactory messageFactory;

    public ListenerController(
        ILogger<ListenerController> logger,
        MessageServiceFactory messageFactory)
    {
        this.logger = logger;
        this.messageFactory = messageFactory;
    }

    [HttpPost]
    public async Task<IActionResult> Post()
    {
        var payload = new
        {
            ...
        };

        await messageFactory.GetMessagingService().Publish(payload);

        return Ok(
            new GDMSResponse()
            {
                ProcessedDate = DateTime.Now,
                SuccessFlag = true
            }
        );
    }
}

1 Ответ

3 голосов
/ 27 мая 2020

Это требует перезапуска после изменения конфигурации, но я не вижу проблем в этом.

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton(Configuration);

    services.AddScoped<IMassTransitRabbitMqTransport, MassTransitRabbitMqTransport>();
    services.AddScoped<IMassTransitAzureServiceBusTransport, MassTransitAzureServiceBusTransport>();

    var messageProvider = Configuration.GetConfig("MessageService", "Messaging_Service");
    switch(messageProvider)
    {
        case "AzureServiceBus": 
            services.AddScoped<IMessagingService, MassTransitAzureServiceBusMessagingService>();
            break;
        case "RabbitMq": 
            services.AddScoped<IMessagingService, MassTransitRabbitMqMessagingService>();
            break;
        default: 
            throw new ArgumentException("Invalid message service");
    };

    services.AddControllers();
}

Другое примечание

Я заметил, что вы поставили как бетонный тип, так и завод:

services.AddScoped<IMessagingService, MassTransitAzureServiceBusMessagingService>(s => s.GetService<MassTransitAzureServiceBusMessagingService>());

Думаю, должно быть:

services.AddScoped<IMessagingService>(s => s.GetService<MassTransitAzureServiceBusMessagingService>());

Не уверен, что это делает разница.

...