简体   繁体   English

.net-core依赖注入

[英].net-core Dependency Injection

I have a Generic repository which I want to register for DI, it implements an interface IRepository. 我有一个Generic存储库,我想注册DI,它实现了一个接口IRepository。

Normally I would create an instance of it like this: 通常我会像这样创建一个实例:

IRepository repo = new Repository<Order>();

However I am trying to get up to speed in .net 5 ahead of release and want to get this working with DI, I have resorted to the following : 但是,我试图在发布之前加快.net 5的速度,并希望将其与DI一起使用,我采用了以下方法:

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

But this feels wrong, I don't want 50+ lines in there one for each of the classes in my model... 但这感觉不对,我不希望在我的模型中的每个类中都有50多行...

I cannot find anything online about this, I know its possible with other ioc containers.. but as this is a learning project I dont want to use another container, Im aiming to do it all with .net5s native container. 我在网上找不到任何关于此的信息,我知道它可能与其他ioc容器有关..但由于这是一个学习项目,我不想使用另一个容器,我的目标是用.net5s原生容器完成所有工作。

您应该能够注册开放通用

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

After some back and forwards in the comments to other answers I have a working solution, It might not be the best way but it works. 在对其他答案的评论中进行了一些反馈和转发后,我有一个有效的解决方案,它可能不是最好的方式,但它有效。 Ill update again if I find a better way to implement this. 如果我找到更好的方法来实现这个,我会再次更新。

The two issues I had were : Needed to register a generic interface, the issue here was a lapse in concentration on my part.. I had the syntax wrong for registering a generic type which of course is : 我遇到的两个问题是:需要注册一个通用接口,这里的问题是我的注意力集中。我注册了泛型类型的语法错误当然是:

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

The second issue was that I have an assembly which contains 50+ different models which I wanted registered, The way that I addressed this was to write a method that I can pass a list of assemblies to along with the Namespace that I want to register and it iterates over any types that match the criteria and registers them in the DI container. 第二个问题是我有一个包含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));
            }
        }
    }

This is then called from the startup.cs method ConfigureServices : 然后从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<>));
    }

There may be a better way to do this, there definitely is using different DI containers, if anyone has improvements to offer please let me know. 可能有更好的方法来做到这一点,肯定有使用不同的DI容器,如果有人提供改进请告诉我。

You could use a convention based registration library like Scrutor . 您可以使用基于会议的注册库,如Scrutor

Scrutor is a small open source library that provides a fluent API to register services in your Microsoft.Extensions.DependencyInjection container based on conventions (Similar to Autofac's RegisterAssemblyTypes method, StructureMap's Scan method and Ninject's Conventions package). Scrutor是一个小型开源库,它提供了一个流畅的API,可以根据约定在Microsoft.Extensions.DependencyInjection容器中注册服务(类似于Autofac的RegisterAssemblyTypes方法,StructureMap的Scan方法和Ninject的约定包)。

This will allow you to do something like this: 这将允许您执行以下操作:

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

What you can do is create an extension method to encapsulate all those individual items that need to be registered. 您可以做的是创建一个扩展方法来封装所有需要注册的单个项目。

That is the same technique Microsoft is using, for example you only put this in startup: 这与Microsoft正在使用的技术相同,例如您只在启动时使用它:

services.AddMvc();

but that is an extension method and behind the scenes you can bet it is registering a bunch of stuff it needs. 但这是一种扩展方法,在幕后你可以打赌它正在注册它需要的一堆东西。

so you can create your own extension method like this: 所以你可以像这样创建自己的扩展方法:

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

    return services;
}

and by making the method return the IServiceCollection you make it fluent so you can do 并通过使该方法返回IServiceCollection,你可以使它流畅,所以你可以做

services.AddMyFoo().AddSomeOtherFoo();

Updated based on comment 根据评论更新

the other technique to reduce registrations is when your dependency doesn't itself have dependencies you can make the constructor have a default of null so you still have decoupling and could pass a different one in later but the DI won't throw an error and you can just instantiate what you need if it is not passed in. 另一种减少注册的技术是当你的依赖本身不具有依赖关系你可以使构造函数的默认值为null,这样你仍然可以解耦并在以后传递一个不同的但是DI不会抛出错误而你如果没有传入,你可以实例化你需要的东西。

public class MyFoo(IFooItemDependency myItem = null)
{
    private IFooItemDependency internalItem;

    public MyFoo(IFooItemDependency myItem = null)
    {
        internalItem = myItem ?? new FooItemItem();
    }
}

I'm not 100% sure on what your question is I assume you don't want to have 我不是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>>();

etc 等等

I have done this before (with ninject) 我之前做过这个(用ninject)

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

I imagine for Unity you can do something similar like 我认为对于Unity你可以做类似的事情

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

And then to use it in a service 然后在服务中使用它

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

EDIT 编辑

As pointed out by OP the correct syntax is: 正如OP指出的那样,正确的语法是:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM