.net-coredependency injection
我有一个Generic存储库,我想注册DI,它实现了一个接口IRepository。
通常我会像这样创建一个它的实例:
IRepository repo = new Repository();
但是我试图在发布之前加速.net 5,并希望将其与DI一起使用,我采用了以下方法:
services.AddTransient<DAL.IRepository, DAL.Repository>();
但这感觉不对,我不希望在我的模型中的每个类中都有50多行…
我在网上找不到任何关于此的内容,我知道它可能与其他ioc容器有关..但由于这是一个学习项目,我不想使用另一个容器,我的目标是用.net5s本机容器来完成所有这些。
您应该能够注册开放通用
services.AddTransient(typeof(IRepository<>), typeof(Repository<>));
在对其他答案的评论中进行了一些回复和转发后,我有一个有效的解决方案,它可能不是最好的方式,但它有效。 如果我找到更好的方法来实现这个,我会再次更新。
我遇到的两个问题是:需要注册一个通用接口,这里的问题是我的注意力集中。我注册了一个通用类型的语法错误当然是:
services.AddTransient(typeof(IRepository<>), typeof(Repository<>));
第二个问题是我有一个包含50多个我想要注册的不同模型的程序集。我解决这个问题的方法是编写一个方法,我可以将程序集列表与我想要注册的Namespace一起传递给它迭代任何符合条件的类型,并将它们注册到DI容器中。
public void RegisterModels(IServiceCollection services, string[] Assemblies, string @NameSpace) { foreach (var a in Assemblies) { Assembly loadedAss = Assembly.Load(a); var q = from t in loadedAss.GetTypes() where t.IsClass && !t.Name.Contains("<") && t.Namespace.EndsWith(@NameSpace) select t; foreach (var t in q.ToList()) { Type.GetType(t.Name); services.AddTransient(Type.GetType(t.FullName), Type.GetType(t.FullName)); } } }
然后从startup.cs方法ConfigureServices调用它:
public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddEntityFramework() .AddSqlServer() .AddDbContext(options => options.UseSqlServer(@"Server=LOCALHOST\SQLEXPRESS;Database=Test;Trusted_Connection=True;")); services.AddMvc(); RegisterModels(services, new string[] { "UI" }, "UI.Models"); services.AddTransient(typeof(IRepository<>), typeof(Repository<>)); }
可能有更好的方法来做到这一点,肯定有使用不同的DI容器,如果有人提供改进请告诉我。
您可以使用基于会议的注册库,如Scrutor 。
Scrutor是一个小型开源库,它提供了一个流畅的API,可以根据约定在Microsoft.Extensions.DependencyInjection容器中注册服务(类似于Autofac的RegisterAssemblyTypes方法,StructureMap的Scan方法和Ninject的约定包)。
这将允许您执行以下操作:
services.Scan(scan => scan .FromAssemblies(<>.GetTypeInfo().Assembly) .AddClasses(classes => classes.Where(x => { var allInterfaces = x.GetInterfaces(); return allInterfaces.Any(y => y.GetTypeInfo().IsGenericType && y.GetTypeInfo().GetGenericTypeDefinition() == typeof(IRepository<>))); })) .AsSelf() .WithTransientLifetime() );
您可以做的是创建一个扩展方法来封装所有需要注册的单个项目。
这与Microsoft正在使用的技术相同,例如您只在启动时使用它:
services.AddMvc();
但这是一种扩展方法,在幕后你可以打赌它正在注册一堆它需要的东西。
所以你可以像这样创建自己的扩展方法:
using Microsoft.Extensions.DependencyInjection; public static IServiceCollection AddMyFoo(this IServiceCollection services) { services.AddTransient, DAL.Repository>(); //.... return services; }
并通过使该方法返回IServiceCollection,你可以使它流畅,所以你可以做
services.AddMyFoo().AddSomeOtherFoo();
根据评论更新
另一种减少注册的技术是,当你的依赖项本身没有依赖项时,你可以使构造函数的默认值为null,这样你仍然可以解耦并在以后传递一个不同的但是DI不会抛出错误而你如果没有传入,你可以实例化你需要的东西。
public class MyFoo(IFooItemDependency myItem = null) { private IFooItemDependency internalItem; public MyFoo(IFooItemDependency myItem = null) { internalItem = myItem ?? new FooItemItem(); } }
我不是100%肯定你的问题我认为你不想拥有
services.AddTransient, DAL.Repository>(); services.AddTransient, DAL.Repository>(); services.AddTransient, DAL.Repository>();
等等
我之前做过这个(用ninject)
Bind(typeof(IRepository<>)).To(typeof(Repository<>)).InRequestScope();
我想,对于Unity你可以做类似的事情
services.AddTransient, typeof(Repository<>)();
然后在服务中使用它
public OrderService(IRepository orderRepository) { this.orderRepository = orderRepository; }
编辑
正如OP指出的那样,正确的语法是:
services.AddTransient(typeof(IRepository<>), typeof(Repository<>));
- 如何从.net核心中的appsettings.json中提取列表
- 在blazor应用程序中自动注入javascript
- 对于未经身份validation的重定向到URL而不是401
- 将google idToken替换为本地openId令牌c#
- entity framework核心 – 将小数精度和比例设置为所有小数属性
- 未指定authenticationScheme,并且未找到DefaultChallengeScheme Cookies身份validation
- 在ASP.NET5控制台应用程序中使用Startup类
- 在.NET Core中将视图返回为字符串
- EF 7(核心)。 像AddTransient一样创建DBContext