发布:2022/1/17 22:46:35作者:管理员 来源:本站 浏览次数:1035
什么是泛型依赖注入
创建两个带泛型的类,并配置两者的依赖关系,对于继承这两个类的子类,如果泛型相同,则会继承这种依赖关系:
如上图:
定义了两个泛型base类:BaseService和BaseRepository
对于UserService和UserRpository分别继承两个base类,泛型都是User,则他们俩继承了父类的依赖关系。
那么在.net core里面怎么实现泛型依赖注入呢
一、安装Autofac
先看项目结构
IMyRepository定义仓储接口
public interface IMyRepository<T> where T: class
{
string GetTypeof();
}
MyRepositoryBase仓储实现
public class MyRepositoryBase<T> : IMyRepository<T> where T : class
{
public string GetTypeof()
{
return typeof(T).Name; //通过typeof可以知道泛型的名字
}
}
CustomAutofacModule 公共的依赖注入类
public class CustomAutofacModule : Module
{
public CustomAutofacModule(ContainerBuilder builder) {
}
/// <summary>
/// AutoFac注册类
/// </summary>
/// <param name="builder"></param>
protected override void Load(ContainerBuilder builder)
{
builder.RegisterGeneric(typeof(MyRepositoryBase<>)).As(typeof(IMyRepository<>)).InstancePerDependency();//注册仓储泛型
//builder.RegisterGeneric(typeof(MyRepositoryBase<,>)).As(typeof(IMyRepository<,>)).InstancePerDependency();//注册仓储泛型 2个以上的泛型参数
// builder.RegisterType<myAssembly>().As<ImyAssembly>(); //普通依赖注入
}
}
在Program声明实现依赖注入
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
//改用Autofac来实现依赖注入
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
修改Startup,运行时候触发CustomAutofacModule
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
//autofac 新增
public ILifetimeScope AutofacContainer { get; private set; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
}
public void ConfigureContainer(ContainerBuilder builder)
{
// 直接用Autofac注册我们自定义的
builder.RegisterModule(new CustomAutofacModule(builder));
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
//autofac 新增
this.AutofacContainer = app.ApplicationServices.GetAutofacRoot();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
在Home控制器中使用
[ApiController]
[Route("[controller]")]
public class HomeController : ControllerBase
{
//public IMyRepository<User> _UserServer { get; set; }
private readonly IMyRepository<User> _UserServer;
private readonly IMyRepository<Role> _RoleServer;
public HomeController(IMyRepository<User> UserServer, IMyRepository<Role> RoleServer)
{
_UserServer = UserServer;
_RoleServer = RoleServer;
}
[Route("Get")]
public string Get() {
return _UserServer.GetTypeof();//"user"; //
}
[Route("GetRole")]
public string GetRole()
{
return _RoleServer.GetTypeof();//"role"; //
}
}
可以看到 不同的地方实现不同的对象
番外:
我是因为看到ABP框架的IRepository的实现才研究泛型依赖注入的用法的。
ABP框架吧Autofac已经 封装为IocManager 了
所以ABP框架不需要 引入Autofac框架。只需要在对应的XXXCoreModule 中的Initialize()方法声明依赖注入便可
IocManager.Register(typeof(IMyRepository<>), typeof(MyRepositoryBase<>), DependencyLifeStyle.Transient);
如果是2个以上的泛型写法是
IocManager.Register(typeof(IAmbientScopeProvider<,>), typeof(DataContextAmbientScopeProvider<,>), DependencyLifeStyle.Transient);
DependencyLifeStyle.Transient 的作用
Transient :瞬态,要么作用域是整个进程,要么作用域是一个请求,而这里的 Transient 就没有作用域概念了,注入一次 实例化一次 最明显的区别,属性注入是不可用的,只能构造函数注入
Singleton:可以在你的进程中保持着一个实例,也就是说仅有一次实例化 最明显的区别,属性注入是可用的
番外2:
看到了很多教程是不用声明CustomAutofacModule类的直接在Startup声明依赖注入就可以的。但是那是core 2.0的写法。core 3.0 下面的写法是会报错的
public static IContainer AutofacContainer;
// This method gets called by the runtime. Use this method to add services to the container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
//注册服务进 IServiceCollection
services.AddMvc();
ContainerBuilder builder = new ContainerBuilder();
//将services中的服务填充到Autofac中.
builder.Populate(services);
//新模块组件注册
builder.RegisterModule<DefaultModuleRegister>();
//创建容器.
AutofacContainer = builder.Build();
//使用容器创建 AutofacServiceProvider
return new AutofacServiceProvider(AutofacContainer);
}