Asp.Net Core DI的服务的配置范围

时间:2018-07-24 08:58:04

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

是否可以为Asp.Net Core中的默认DI设置注入范围?我的意思是例如:

services.AddSingleton<IUser, UserService>
services.AddSingleton<IUser, UserService>

对于第二种配置,以某种方式指定应仅将其注入到HomeController中。与第一个不同,应该将其注入所有其他对象。默认的DI可以吗?

3 个答案:

答案 0 :(得分:0)

我相信您可以为特定控制器指定特殊注入。

 public void ConfigureServices(IServiceCollection services)
 {
        services.AddMvc();

        services.AddScoped<TestService>();
        services.AddTransient(ctx =>
            new HomeController(new TestService("Non-default value")));
 }

tutorial具有更深的解释。

第二种可能被认为是解决方法的方法是注册一个基于名称的函数,该函数返回不同的服务实现。我以前使用过like this

答案 1 :(得分:0)

假设进行此注册,则依赖项注入容器应该如何知道应该将哪个“单身”(当其中有两个时不是一个单例)注入到HomeController或另一个服务中,而它们都只是依赖在IUser上?

在您的情况下IUser中,依赖项被注册为的类型是DI容器用来解析依赖项的“键”。因此,两个都依赖于IUser的服务将以相同的方式解决它们的依赖关系。单例生存期意味着这两个服务将获得相同的实例。

服务注册通常也可以代替。因此,如果您有一个注册AddSingleton<X, Y>(),然后又有另一个AddSingleton<X, Z>(),则后者将替换。因此,所有依赖X的服务都将收到Z

DI容器(包括ASP.NET Core附带的默认容器)通常确实支持通过解析IEnumerable<X>来解析 all 注册。但是对于此示例,这仅意味着服务将同时获得YZ

您正在寻找的最接近的东西是键控或命名依赖项。虽然这些在 some DI容器中受支持,但从技术上讲,它们不是依赖项注入的一部分,因此deliberately absent通常来自许多容器,包括ASP.NET Core。 See this answer,以获取更多详细信息并解决该问题。


要回到您的用例,您应该真正考虑一下您在这里实际做什么。如果您有两个UserService的“单例”实例,那么您应该真正想到为什么的情况:为什么不只有一个?如果支持多个,为什么不将其注册为瞬态?

更重要的是,这两个实例之间可能会有什么不同?毕竟,它们都是同一实现的实例,因此它们可以做的事情不多。

如果您可以识别出这一点,并且还确认这确实使实例与众不同,那么也可以考虑将其拆分为类型层次结构。没有此处的用例很难解释这一点,但是您应该尝试以两个different interfaces that each do exactly what each dependent service type needs结尾。因此,HomeController可以依赖IUserA,其他人可以依赖IUserB(请选择比这更好的名称)。

答案 2 :(得分:0)

我在这里回答了类似的问题,但是使用了作用域而不是单例:

How to register multiple implementations of the same interface in Asp.Net Core?

我的直觉是,这可能是您要实现的目标,或者可能是更好的方法,并且您可能会将User与UserService混淆了。当您具有同一接口的多个实现时,DI会将它们添加到集合中,因此可以使用typeof从集合中检索所需的版本。

// In Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped(IUserService, UserServiceA);
    services.AddScoped(IUserService, UserServiceB);
    services.AddScoped(IUserService, UserServiceC);
}

// Any class that uses the service(s)
public class Consumer
{
    private readonly IEnumerable<IUserService> _myServices;

    public Consumer(IEnumerable<IUserService> myServices)
    {
        _myServices = myServices;
    }

    public UserServiceA()
    {
        var userServiceA = _myServices.FirstOrDefault(t => t.GetType() == typeof(UserServiceA));
        userServiceA.DoTheThing();
    }

    public UserServiceB()
    {
        var userServiceB = _myServices.FirstOrDefault(t => t.GetType() == typeof(UserServiceB));
        userServiceB.DoTheThing();
    }

    public UseServiceC()
    {
        var userServiceC = _myServices.FirstOrDefault(t => t.GetType() == typeof(UserServiceC));
        userServiceC.DoTheThing();
    }
}