如前所述,一个服务可以注入另一个服务中。这也可以用来初始化一个带有选项的服务。不能使用服务的构造函数定义非服务协定来进行初始化,因为容器不知道如何初始化它。服务是必要的。但是,为了传递服务的选项,还可以使用已经可用于.NET Core的服务。
示例DIWithOptions使用这些NuGet包和名称空间:
包
Microsoft.Extensions.DependencyInjection
Microsoft.Extensions.Options
名称空间
System
Microsoft.Extensions.DependencyInjection
Microsoft.Extensions.Options
示例代码使用之前使用的GreetingService进行修改,以传递选项。服务所需的配置值由类GreetingServiceOptions定义。样例代码需要一个带有From属性的String参数:
public class GreetingServiceOptions
{
public string From { get; set; }
}
可以指定带有IOptions<T>参数的构造函数,来传递服务的选项。前面定义的类GreetingServiceOptions是用于IOptions的泛型类型。传递给构造函数的值用于初始化字段_from:
class GreetingService : IGreetingService
{
public GreetingService(IOptions<GreetingServiceOptions> options) => _from = options.Value.From;
private string _from;
public string Greet(string name) => $"Hello,{name}!Greeting from {_from}";
}
注意:
IOptions接口和用于选项的服务在NuGet包Microsoft.Extensions.Options中实现。
为了便于使用DI容器注册服务,定义了扩展方法AddGreetingSercvice。该方法扩展了IServiceCollection接口,并允许通过委托传递GreetingServiceOptions。在实现代码中,Configure方法用于通过IOptions接口指定配置。Configure方法是NuGet包Microsoft.Extensions.Options中IServicesCollection的扩展方法:
static class GreetingServiceExtensions
{
public static IServiceCollection AddGreetingService(this IServiceCollection collection,Action<GreetingServiceOptions> setupActoin)
{
if (collection == null)
{
throw new ArgumentNullException(nameof(collection));
}
if (setupActoin == null)
{
throw new ArgumentNullException(nameof(setupActoin));
}
collection.Configure(setupActoin);
return collection.AddTransient<IGreetingService,GreetingService>();
}
}
通过构造函数注入使用GreetingService的HomeController不需要任何更改:
class HomeController
{
private readonly IGreetingService _greetingService;
private HomeController(IGreetingService greetingService)
{
_greetingService = greetingService;
}
public string Hello(string name) => _greetingService.Greet(name);
}
现在可以使用辅助方法AddGreetingService注册服务。GreetingService的配置是通过传递所需选项来完成的。还需要一个实现IOptions接口的服务。在这里,可以使用扩展方法AddOptions。该方法添加了几个接口,并将其映射到与选项一起使用的实现:
static ServiceProvider RegisterService()
{
var services = new ServiceCollection();
//services.AddOptions();//注释后,也可以正常运行
services.AddGreetingService(options =>
{
options.From = "Christian";
});
services.AddTransient<HomeController>();
return services.BuildServiceProvider();
}
该服务现在可以像以前一样使用。HomeController从容器中检索,在使用IGreetingService的HomeController中使用构造函数注入:
static void Main(string[] args)
{
//Console.WriteLine("Hello World!");
using (var container = RegisterService())
{
var controller = container.GetRequiredService<HomeController>();
string result = controller.Hello("Katharina");
Console.WriteLine(result);
}
}
static ServiceProvider RegisterService()
{
var services = new ServiceCollection();
//services.AddOptions();//注释后,也可以正常运行
services.AddGreetingService(options =>
{
options.From = "Christian";
});
services.AddTransient<HomeController>();
return services.BuildServiceProvider();
}
运行应用程序时,现在可以使用以下选择:
Hello,Katharina!Greeting from Christian