簡體   English   中英

.將工廠模式與 .NET Core 3.1 依賴注入結合使用

[英].Using a Factory Pattern with NET Core 3.1 Dependency Injection

我有一個 .NET Core 3.1 API 可能正在使用 RabbitMq 或 Azure 服務總線。 選擇將通過配置參數確定。 由於要使用的配置是運行時決定的,我希望將工廠模式與 .NET Core 的依賴注入一起使用。 我在https://medium.com/@mailbox.viksharma/factory-pattern-using-built-in-dependency-injection-of-asp.net-core-f91bd3b58665找到了一篇文章,但無法讓工廠工作。 任何幫助將不勝感激。

由於 IServiceProvider,問題發生在工廠 class 內。 我在嘗試 GetService 時收到錯誤System.NullReferenceException: Object 引用未設置為 object 的實例

工廠 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)
    {
        ....
    }
}

在 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();
    }

Controller

[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
            }
        );
    }
}

這需要在更改配置后重新啟動,但我認為這樣做沒有問題。

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>());

不確定它是否有所作為。

2021 年 1 月更新最近我不得不自己做這件事並想出了這個解決方案:

public static IServiceCollection ConfigureEventBus(this IServiceCollection services, IConfiguration configuration)
{
    var queueSettings = new QueueSettings();
    configuration.GetSection("QueueSettings").Bind(queueSettings);

    if (configuration.GetValue<bool>("AzureServiceBusEnabled"))
    {
        services.AddMassTransit(x =>
        {
            x.UsingAzureServiceBus((context, cfg) =>
            {
                cfg.Host(queueSettings.HostName);
            });
        });
    }
    else
    {
        services.AddMassTransit(x =>
        {
            x.UsingRabbitMq((context, cfg) =>
            {
                cfg.ConfigureEndpoints(context);
                cfg.Host(queueSettings.HostName, queueSettings.VirtualHost, h =>
                {
                    h.Username(queueSettings.UserName);
                    h.Password(queueSettings.Password);
                });
            });
        });
    }

    services.AddMassTransitHostedService();
    services.AddSingleton<IEventBus, MassTransitEventBus>();

    return services;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM