.在 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 中。我收到错误 System.NullReferenceException:对象引用未设置到对象的实例。 来自对 GetService 的尝试。
工厂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();
}
控制器
[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;
}
我有一个 .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 中。我收到错误 System.NullReferenceException:对象引用未设置到对象的实例。 来自对 GetService 的尝试。
工厂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();
}
控制器
[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;
}