繁体   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