有关服务的生命周期
尽可能将您的服务注册为瞬态服务。 因为设计瞬态服务很简单。 您通常不用关心多线程和内存泄漏,并且您知道该服务的寿命很短。
请谨慎使用Scoped,因为如果您创建子服务作用域或从非Web应用程序使用这些服务,则可能会非常棘手。
谨慎使用Singleton,因为您需要处理多线程和潜在的内存泄漏问题。
在Singleton服务中不要依赖Transient或者Scoped服务,因为如果当一个Singleton服务注入Transient服务,这个Transient服务就会变成一个Singleton服务,并且如果Transient服务不是为支持这种情况而设计的,则可能导致问题。 在这种情况下,ASP.NET Core的默认DI容器已经抛出异常。
有关注册的服务使用
- 在我们注册服务后,通常使用的是
构造函数注入
的方式来注入所需依赖项
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class ProductService { private readonly IProductRepository _productRepository; public ProductService(IProductRepository productRepository) { _productRepository = productRepository; } public void Delete(int id) { _productRepository.Delete(id); } }
|
而避免服务定位器
,因为该模式存在隐含的依赖关系,这意味着在创建服务实例时无法轻松查看依赖关系。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class ProductService { private readonly IProductRepository _productRepository; public ProductService(IServiceProvider serviceProvider) { _productRepository = serviceProvider .GetRequiredService<IProductRepository>(); } public void Delete(int id) { _productRepository.Delete(id); } public void ShowMes() { Console.WriteLine("Test"); } }
|
但是有些种情况不适合使用构造函数注入
,如注入的服务的实例的构造函数执行过于慢,如上面IProductRepository
的实例,假设其构造函数需要花费1秒,那就会导致我们就算只是想访问ProductService的方法ShowMes()
时,都需要等待至少1秒,这很糟糕,我们当然可以把该方法单独出来,但这明显不是一个很好的做法。
这时候我们就需要在使用时再用服务定位器
方式获得其实例,如
1 2 3 4 5 6
| public void Delete(int id) { _productRepository = serviceProvider .GetRequiredService<IProductRepository>(); _productRepository.Delete(id); }
|
而在Asp.Net Core中,还有使用FromServices特性修饰的办法
1 2 3 4 5 6 7 8
| public class ValuesController : Controller { [HttpGet] public ActionResult<bool> Get([FromServices] IAccountService accountService, int accId) { return accountService.Validate(accID); } }
|
- 将注入的依赖项分配给只读【readonly】字段/属性(防止在方法内意外地为其分配另外一个值)。
1
| private readonly IProductRepository _productRepository;
|
获取当前注册的所有服务,并打印每个服务对应的声明类型、实现类型和生命周期
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
|
public string GetDIShowList(IServiceCollection services) { StringBuilder sb = new StringBuilder();
sb.AppendLine($"Services Count: {services.Count}"); var provider = services.BuildServiceProvider(); foreach (var service in services) { var serviceTypeName = GetName(service.ServiceType); var implementationType = service.ImplementationType ?? service.ImplementationInstance?.GetType() ?? service.ImplementationFactory?.Invoke(provider)?.GetType(); if (implementationType != null) { sb.AppendLine($"{service.Lifetime,-15} {serviceTypeName,-50}{GetName(implementationType)}"); } }
return sb.ToString();
string GetName(Type type) { if (!type.IsGenericType) { return type.Name; } var name = type.Name.Split('`')[0]; var args = type.GetGenericArguments().Select(it => it.Name); return $"{name}<{string.Join(",", args)}>"; } }
public void ConfigureServices(IServiceCollection services) { var ShowServicesListOnConsole = "true"; if (!string.IsNullOrEmpty(ShowServicesListOnConsole) && ShowServicesListOnConsole.ToLower() == "true") { Console.WriteLine(GetDIShowList(services)); } }
|
最终会显示类似
1 2 3 4 5 6 7 8 9 10 11 12 13
| Services Count: 175 Singleton IHostingEnvironment HostingEnvironment Singleton IHostEnvironment HostingEnvironment Singleton HostBuilderContext HostBuilderContext Singleton IConfiguration ConfigurationRoot Singleton IApplicationLifetime ApplicationLifetime Singleton IHostApplicationLifetime ApplicationLifetime Singleton IHostLifetime ConsoleLifetime Singleton IHost Host Singleton IOptions<TOptions> UnnamedOptionsManager<TOptions> Scoped IOptionsSnapshot<TOptions> OptionsManager<TOptions> Singleton IOptionsMonitor<TOptions> OptionsMonitor<TOptions> ...
|