.NET Core 依赖注入如何处理多个 objects
.NET Core Dependency Injection how to handle multiple objects
正如标题所说,我有一个 .NET Core 应用程序,我正在尝试将其转换并利用内置的 Microsoft 依赖注入。
我有一个 object 和一个 object 的基础 class,称它为 CommunicationBase
和 Communicator
。当我的应用程序启动并读取配置文件时,我可以实例化 N 个 object。
以前,在切换到依赖注入之前,在我的启动例程的某个地方,我读取配置文件的地方,我会有一个 List<CommunicationBase>
变量,我将实例化并添加 Communicator
objects 并同时设置一些基本属性,这些属性根据我的配置中的数量和配置中的每个属性而改变。
我如何使用 DI 实现此目的?
我知道在我的服务中,我会注册类型,以便它可以注入其他 class 构造函数。
例如,services.AddTransient<CommunicationBase, Communicator>();
但据我了解,这只是将类型注册到 DI。我可以将它注入到 class 中,并获得其中一个的随机实例。
然后我将如何拥有 N 个实例并能够在创建实例时设置每个实例的属性?
或者,这是不需要 DI 或 DI 不起作用而我需要按照以前的方式进行的情况吗?
谢谢!
首先你需要清楚Transient、Scoped、Singleton生命周期之间的区别。了解如何使用将从您的配置文件中读取的 Communicator 对象列表。
解决您问题的一种方法是
- 用一种方法创建一个接口 ICommunicatorList 来获取列表,我的意思是你可以包含通讯器列表。
- 创建一个继承自 ICommunicatorList 的类(例如称为 CommunicatorList),其中包含用于您的 Communicator 列表的私有字段。在构造函数方法上,使用通信器列表设置您的私有字段,o 在这里您可以从配置文件的部分接收参数,以迭代和填充您的私有字段。
- 在此 class 上将您的代码实施到 return 通信者列表。
- 现在,您可以在启动文件中创建服务
services.AddTransient< ICommunicatorList>(x => new CommunicatorList(参数));
我会稍微修改显示的方法 here。所以我会定义一些枚举,然后用于决定 return.
的实例
示例 classes 设置和枚举:
public enum CommuniationType
{
False, True, Other,
}
public abstract class CommunicationBase
{
public CommunicationBase(CommuniationType communiationType)
{
CommuniationType = communiationType;
}
public bool IsConnected { get; set; }
public CommuniationType CommuniationType { get; protected set; }
}
public class Communicator : CommunicationBase
{
public Communicator(CommuniationType communiationType) : base(communiationType) { }
}
现在,在您有权访问服务集合的地方(例如,在 ASP.NET 中,该地方将是 Stratup.RegisterServices
方法),您可以定义具体的对象 class 并注册它们, 如下面的示例代码(在底部,还有使用 CommunicationBase
对象测试 puproses 的测试 classes):
public class Program
{
static void Main(string[] args)
{
var serviceCollection = new ServiceCollection();
SetupNObjects(serviceCollection);
serviceCollection.AddTransient<CommunicationBaseServiceResolver>(serviceProvider => communicationType =>
{
var implementations = serviceProvider.GetServices<CommunicationBase>();
return implementations.First(x => x.CommuniationType == communicationType);
});
serviceCollection.AddScoped<FalseTestClass>();
serviceCollection.AddScoped<TrueTestClass>();
var serviceProvider = serviceCollection.BuildServiceProvider();
var f = serviceProvider.GetService<FalseTestClass>();
var t = serviceProvider.GetService<TrueTestClass>();
}
// Here you should take care of registering objects, after reading config.
// That would be best place to do that.
static void SetupNObjects(ServiceCollection serviceCollection)
{
var comFalse = new Communicator(CommuniationType.False);
comFalse.IsConnected = false;
var comTrue = new Communicator(CommuniationType.True);
comTrue.IsConnected = true;
serviceCollection.AddScoped<CommunicationBase>((serviceProvider) => comFalse);
serviceCollection.AddScoped<CommunicationBase>((serviceProvider) => comTrue);
}
}
public class FalseTestClass
{
private readonly CommunicationBase communication;
public FalseTestClass(CommunicationBaseServiceResolver resolver)
{
communication = resolver(CommuniationType.False);
}
}
public class TrueTestClass
{
private readonly CommunicationBase communication;
public TrueTestClass(CommunicationBaseServiceResolver resolver)
{
communication = resolver(CommuniationType.True);
}
}
我会按照以下方式进行。
首先你有通讯器和设置类:
namespace WebApiApp
{
public abstract class CommunicationBase
{
public abstract string Communicate();
}
public class Communicator1Settings
{
public string Parameter { get; set; }
}
public class Communicator1 : CommunicationBase
{
private readonly string parameter;
public Communicator1(string parameter)
{
this.parameter = parameter;
}
public override string Communicate()
{
return $"Type: {nameof(Communicator1)}, parameter: {this.parameter}";
}
}
public class Communicator2Settings
{
public string Parameter1 { get; set; }
public string Parameter2 { get; set; }
}
public class Communicator2 : CommunicationBase
{
private readonly string parameter1;
private readonly string parameter2;
public Communicator2(string parameter1, string parameter2)
{
this.parameter1 = parameter1;
this.parameter2 = parameter2;
}
public override string Communicate()
{
return $"Type: {nameof(Communicator1)}, parameter1: {this.parameter1}, parameter2: {this.parameter2}";
}
}
public class CommunicatorsSettings
{
public List<Communicator1Settings> Communicators1 { get; set; }
public List<Communicator2Settings> Communicators2 { get; set; }
}
}
在appsettings.json中你有通讯器的配置:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Communicators": {
"Communicators1": [
{
"Parameter": "First communicator1 parameter"
},
{
"Parameter": "Second communicator1 parameter"
}
],
"Communicators2": [
{
"Parameter1": "First communicator2 parameter1",
"Parameter2": "First communicator2 parameter2"
},
{
"Parameter1": "Second communicator2 parameter1",
"Parameter2": "Second communicator2 parameter2"
}
]
}
}
因此您有两个 Communicator1
实例具有不同的参数和两个 Communicator2
实例具有不同的参数。
然后,您配置容器。以下是program.cs
for .net 6 的内容:
using WebApiApp;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
AddCommunicators();
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
void AddCommunicators()
{
var settings = new CommunicatorsSettings();
builder.Configuration.Bind("Communicators", settings);
foreach (var communicatorSettings in settings.Communicators1)
{
builder.Services.AddScoped<CommunicationBase>(
_ => new Communicator1(communicatorSettings.Parameter));
}
foreach (var communicatorSettings in settings.Communicators2)
{
builder.Services.AddScoped<CommunicationBase>(
_ => new Communicator2(communicatorSettings.Parameter1, communicatorSettings.Parameter2));
}
}
现在您可以将 IEnumerable<CommunicationBase>
注入您的控制器:
using Microsoft.AspNetCore.Mvc;
namespace WebApiApp.Controllers
{
[ApiController]
[Route("[controller]")]
public class CommunicatorsController : Controller
{
private readonly IEnumerable<CommunicationBase> communicators;
public CommunicatorsController(IEnumerable<CommunicationBase> communicators)
{
this.communicators = communicators;
}
public IActionResult Get()
{
var result = this.communicators.Select(x => x.Communicate());
return this.Json(result);
}
}
}
这是 /communicators
网站的结果 API:
[
"Type: Communicator1, parameter: First communicator1 parameter",
"Type: Communicator1, parameter: Second communicator1 parameter",
"Type: Communicator1, parameter1: First communicator2 parameter1, parameter2: First communicator2 parameter2",
"Type: Communicator1, parameter1: Second communicator2 parameter1, parameter2: Second communicator2 parameter2"
]
正如标题所说,我有一个 .NET Core 应用程序,我正在尝试将其转换并利用内置的 Microsoft 依赖注入。
我有一个 object 和一个 object 的基础 class,称它为 CommunicationBase
和 Communicator
。当我的应用程序启动并读取配置文件时,我可以实例化 N 个 object。
以前,在切换到依赖注入之前,在我的启动例程的某个地方,我读取配置文件的地方,我会有一个 List<CommunicationBase>
变量,我将实例化并添加 Communicator
objects 并同时设置一些基本属性,这些属性根据我的配置中的数量和配置中的每个属性而改变。
我如何使用 DI 实现此目的?
我知道在我的服务中,我会注册类型,以便它可以注入其他 class 构造函数。
例如,services.AddTransient<CommunicationBase, Communicator>();
但据我了解,这只是将类型注册到 DI。我可以将它注入到 class 中,并获得其中一个的随机实例。
然后我将如何拥有 N 个实例并能够在创建实例时设置每个实例的属性?
或者,这是不需要 DI 或 DI 不起作用而我需要按照以前的方式进行的情况吗?
谢谢!
首先你需要清楚Transient、Scoped、Singleton生命周期之间的区别。了解如何使用将从您的配置文件中读取的 Communicator 对象列表。
解决您问题的一种方法是
- 用一种方法创建一个接口 ICommunicatorList 来获取列表,我的意思是你可以包含通讯器列表。
- 创建一个继承自 ICommunicatorList 的类(例如称为 CommunicatorList),其中包含用于您的 Communicator 列表的私有字段。在构造函数方法上,使用通信器列表设置您的私有字段,o 在这里您可以从配置文件的部分接收参数,以迭代和填充您的私有字段。
- 在此 class 上将您的代码实施到 return 通信者列表。
- 现在,您可以在启动文件中创建服务 services.AddTransient< ICommunicatorList>(x => new CommunicatorList(参数));
我会稍微修改显示的方法 here。所以我会定义一些枚举,然后用于决定 return.
的实例示例 classes 设置和枚举:
public enum CommuniationType
{
False, True, Other,
}
public abstract class CommunicationBase
{
public CommunicationBase(CommuniationType communiationType)
{
CommuniationType = communiationType;
}
public bool IsConnected { get; set; }
public CommuniationType CommuniationType { get; protected set; }
}
public class Communicator : CommunicationBase
{
public Communicator(CommuniationType communiationType) : base(communiationType) { }
}
现在,在您有权访问服务集合的地方(例如,在 ASP.NET 中,该地方将是 Stratup.RegisterServices
方法),您可以定义具体的对象 class 并注册它们, 如下面的示例代码(在底部,还有使用 CommunicationBase
对象测试 puproses 的测试 classes):
public class Program
{
static void Main(string[] args)
{
var serviceCollection = new ServiceCollection();
SetupNObjects(serviceCollection);
serviceCollection.AddTransient<CommunicationBaseServiceResolver>(serviceProvider => communicationType =>
{
var implementations = serviceProvider.GetServices<CommunicationBase>();
return implementations.First(x => x.CommuniationType == communicationType);
});
serviceCollection.AddScoped<FalseTestClass>();
serviceCollection.AddScoped<TrueTestClass>();
var serviceProvider = serviceCollection.BuildServiceProvider();
var f = serviceProvider.GetService<FalseTestClass>();
var t = serviceProvider.GetService<TrueTestClass>();
}
// Here you should take care of registering objects, after reading config.
// That would be best place to do that.
static void SetupNObjects(ServiceCollection serviceCollection)
{
var comFalse = new Communicator(CommuniationType.False);
comFalse.IsConnected = false;
var comTrue = new Communicator(CommuniationType.True);
comTrue.IsConnected = true;
serviceCollection.AddScoped<CommunicationBase>((serviceProvider) => comFalse);
serviceCollection.AddScoped<CommunicationBase>((serviceProvider) => comTrue);
}
}
public class FalseTestClass
{
private readonly CommunicationBase communication;
public FalseTestClass(CommunicationBaseServiceResolver resolver)
{
communication = resolver(CommuniationType.False);
}
}
public class TrueTestClass
{
private readonly CommunicationBase communication;
public TrueTestClass(CommunicationBaseServiceResolver resolver)
{
communication = resolver(CommuniationType.True);
}
}
我会按照以下方式进行。
首先你有通讯器和设置类:
namespace WebApiApp
{
public abstract class CommunicationBase
{
public abstract string Communicate();
}
public class Communicator1Settings
{
public string Parameter { get; set; }
}
public class Communicator1 : CommunicationBase
{
private readonly string parameter;
public Communicator1(string parameter)
{
this.parameter = parameter;
}
public override string Communicate()
{
return $"Type: {nameof(Communicator1)}, parameter: {this.parameter}";
}
}
public class Communicator2Settings
{
public string Parameter1 { get; set; }
public string Parameter2 { get; set; }
}
public class Communicator2 : CommunicationBase
{
private readonly string parameter1;
private readonly string parameter2;
public Communicator2(string parameter1, string parameter2)
{
this.parameter1 = parameter1;
this.parameter2 = parameter2;
}
public override string Communicate()
{
return $"Type: {nameof(Communicator1)}, parameter1: {this.parameter1}, parameter2: {this.parameter2}";
}
}
public class CommunicatorsSettings
{
public List<Communicator1Settings> Communicators1 { get; set; }
public List<Communicator2Settings> Communicators2 { get; set; }
}
}
在appsettings.json中你有通讯器的配置:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Communicators": {
"Communicators1": [
{
"Parameter": "First communicator1 parameter"
},
{
"Parameter": "Second communicator1 parameter"
}
],
"Communicators2": [
{
"Parameter1": "First communicator2 parameter1",
"Parameter2": "First communicator2 parameter2"
},
{
"Parameter1": "Second communicator2 parameter1",
"Parameter2": "Second communicator2 parameter2"
}
]
}
}
因此您有两个 Communicator1
实例具有不同的参数和两个 Communicator2
实例具有不同的参数。
然后,您配置容器。以下是program.cs
for .net 6 的内容:
using WebApiApp;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
AddCommunicators();
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
void AddCommunicators()
{
var settings = new CommunicatorsSettings();
builder.Configuration.Bind("Communicators", settings);
foreach (var communicatorSettings in settings.Communicators1)
{
builder.Services.AddScoped<CommunicationBase>(
_ => new Communicator1(communicatorSettings.Parameter));
}
foreach (var communicatorSettings in settings.Communicators2)
{
builder.Services.AddScoped<CommunicationBase>(
_ => new Communicator2(communicatorSettings.Parameter1, communicatorSettings.Parameter2));
}
}
现在您可以将 IEnumerable<CommunicationBase>
注入您的控制器:
using Microsoft.AspNetCore.Mvc;
namespace WebApiApp.Controllers
{
[ApiController]
[Route("[controller]")]
public class CommunicatorsController : Controller
{
private readonly IEnumerable<CommunicationBase> communicators;
public CommunicatorsController(IEnumerable<CommunicationBase> communicators)
{
this.communicators = communicators;
}
public IActionResult Get()
{
var result = this.communicators.Select(x => x.Communicate());
return this.Json(result);
}
}
}
这是 /communicators
网站的结果 API:
[
"Type: Communicator1, parameter: First communicator1 parameter",
"Type: Communicator1, parameter: Second communicator1 parameter",
"Type: Communicator1, parameter1: First communicator2 parameter1, parameter2: First communicator2 parameter2",
"Type: Communicator1, parameter1: Second communicator2 parameter1, parameter2: Second communicator2 parameter2"
]