!!! 本文已参与「新人创作礼」活动,一起开启掘金创作之路。更多干货文章,可以访问 菜鸟厚非
介绍
用过 ASP.NET Core 的朋友都知道,默认的 IoC 容器它提供了基本的 AddXXXX 方法来绑定实例关系,但是对于大型项目来说,还是挺困难的,大型的项目需要的是通用的注册,不可能手动添加每个对象的解析关系,这才是我们面临的痛点。
解决方案
- 可以继续使用默认的 IoC 容器通过程序初始化加载进行注册,还可以使用第三方 Castle Windsor 替换 ASP.NET Core 默认容器,本篇讲解使用 默认 IoC 容器方式。
默认 IoC 容器
- 定义三种生命周期不同的接口 ITransientDependency、ISingletonDependency、IScopedDependency ,具体不做解锁根据英文单词也应该知道
public interface ITransientDependency
{
}
public interface ISingletonDependency
{
}
public interface IScopedDependency
{
}
- ServiceCollection 扩展方法
public static class ServiceCollectionExtension
{
public static void ServiceRegister(this IServiceCollection services, params Assembly[] assemblies)
{
if (assemblies.Count() <= 0)
{
return;
}
foreach (var assembly in assemblies)
{
var allTypes = assembly.GetTypes();
foreach (var type in allTypes)
{
if (typeof(ITransientDependency).IsAssignableFrom(type) && type.IsClass && !type.IsAbstract)
{
// 获取当前实现类的接口,但不包含我们的标记类
var interfaceTypes = type.GetInterfaces().Where(p => !p.FullName.Contains("ITransientDependency"));
foreach (var interfaceType in interfaceTypes)
{
services.AddTransient(interfaceType,type);
}
}
}
foreach (var type in allTypes)
{
if (typeof(ISingletonDependency).IsAssignableFrom(type) && type.IsClass && !type.IsAbstract)
{
// 获取当前实现类的接口,但不包含我们的标记类
var interfaceTypes = type.GetInterfaces().Where(p => !p.FullName.Contains("ISingletonDependency"));
foreach (var interfaceType in interfaceTypes)
{
services.AddSingleton(interfaceType, type);
}
}
}
foreach (var type in allTypes)
{
if (typeof(IScopedDependency).IsAssignableFrom(type) && type.IsClass && !type.IsAbstract)
{
// 获取当前实现类的接口,但不包含我们的标记类
var interfaceTypes = type.GetInterfaces().Where(p => !p.FullName.Contains("IScopedDependency"));
foreach (var interfaceType in interfaceTypes)
{
services.AddScoped(interfaceType, type);
}
}
}
}
}
}
- 注册服务,在正式应用场景中,我们是非常可能需要把多个程序集都按约定来注册的,个人建议的做法是,在每个需要注册的程序集中添加一个标志该程序集的基类,比如在 Service 这个程序集中添加一个 IServiceBase 接口,这样就可以通过typeof(IServiceBase).Assembly 获取到这个程序集进而用来注册
public void ConfigureServices(IServiceCollection services)
{
services.ServiceRegister(Assembly.GetExecutingAssembly());
}
- 按约定进行继承
public interface IPostBlogService : ITransientDependency
{
Result Post(BlogDto dto);
}
public class PostBlogService : IPostBlogService
{
public Result Post(BlogDto dto)
{
//todo: post this blog
}
}
- 总结 三个生命周期标记接口,只是都属于一种约定,基于约定进行注册,只是容器不一样而已。你可能有疑惑,你每次都扫描进程集效率会不会很低,其实 ConfigureServices 只是在你应用启动时才运行一次,也就是说我们只扫描一次进程集,不存在性能问题。