.net-core依赖注入

时间:2016-02-11 14:47:49

标签: c# dependency-injection inversion-of-control asp.net-core

我有一个Generic存储库,我想注册DI,它实现了一个接口IRepository。

通常我会像这样创建一个实例:

IRepository repo = new Repository<Order>();

然而,我试图在发布之前加快.net 5的速度,并希望将其与DI合作,我采取了以下措施:

services.AddTransient<DAL.IRepository<Models.Order>, DAL.Repository<Models.Order>>();

但是这感觉不对,我不希望在我的模型中的每个类中有50多行...

我在网上找不到任何关于此的内容,我知道它可能与其他ioc容器有关..但由于这是一个学习项目,我不想使用另一个容器,我的目标是用.net5s原生容器来完成。

5 个答案:

答案 0 :(得分:11)

您应该可以使用

注册开放通用
services.AddTransient(typeof(IRepository<>), typeof(Repository<>));

答案 1 :(得分:4)

在对其他答案的评论中进行了一些回复和转发后,我有一个有效的解决方案,它可能不是最好的方式,但它有效。如果我找到更好的方法来实现这个,我会再次更新。

我遇到的两个问题是:需要注册一个通用接口,这里的问题是我的注意力集中。我注册了一个通用类型的语法错误当然是:

services.AddTransient(typeof(IRepository<>), typeof(Repository<>));

第二个问题是我有一个包含50多个我想要注册的不同模型的程序集。我解决这个问题的方法是编写一个方法,我可以将程序集列表与我想要的命名空间一起传递注册并迭代符合条件的任何类型,并将它们注册到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<TestContext>(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容器,如果有人提供改进请告诉我。

答案 2 :(得分:2)

您可以使用基于约定的注册库,例如Scrutor

Scrutor是一个小型开源库,它提供了一个流畅的API,可以根据约定在Microsoft.Extensions.DependencyInjection容器中注册服务(类似于Autofac的RegisterAssemblyTypes方法,StructureMap的Scan方法和Ninject的约定包)。

这将允许您执行以下操作:

services.Scan(scan => scan
            .FromAssemblies(<<TYPE>>.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()
        );

答案 3 :(得分:0)

您可以做的是创建一个扩展方法来封装所有需要注册的单个项目。

这与Microsoft正在使用的技术相同,例如您只在启动时使用它:

services.AddMvc();

但这是一种扩展方法,在幕后你可以打赌它正在注册一堆它需要的东西。

所以你可以像这样创建自己的扩展方法:

using Microsoft.Extensions.DependencyInjection;
public static IServiceCollection AddMyFoo(this IServiceCollection services)
{
    services.AddTransient<DAL.IRepository<Models.Order>, DAL.Repository<Models.Order>>();
    //....

    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();
    }
}

答案 4 :(得分:0)

我不能100%确定你的问题是什么我认为你不想拥有

services.AddTransient<DAL.IRepository<Models.Order>, DAL.Repository<Models.Order>>();
services.AddTransient<DAL.IRepository<Models.Person>, DAL.Repository<Models.Person>>();
services.AddTransient<DAL.IRepository<Models.Invoice>, DAL.Repository<Models.Invoice>>();

我之前(使用ninject)

Bind(typeof(IRepository<>)).To(typeof(Repository<>)).InRequestScope();

我认为对于Unity你可以做类似

的事情
services.AddTransient<DAL.IRepository<>, typeof(Repository<>)();

然后在服务中使用它

public OrderService(IRepository<Models.Order> orderRepository)
{
    this.orderRepository = orderRepository;
}

修改

正如OP所指出的,正确的语法是:

services.AddTransient(typeof(IRepository<>), typeof(Repository<>));