asp.net 依赖注入_ASP.NET中的依赖注入练习:简介

asp.net 依赖注入

在本文中,我们将做一些练习来介绍ASP.NET中DI(依赖注入)的基础知识。

辅助功能级别

以下代码的结果是什么?

public interface IServiceA { }

class ServiceA : IServiceA
{
    ServiceA()
    {
        Console.WriteLine( "New SA" );
    }
}

public class Startup
{
    public void ConfigureServices ( IServiceCollection services )
    {
        services.AddTransient<IServiceA, ServiceA>();
        ...
    }
}

它将引发异常:

System.AggregateException: 'Some services are not able to be constructed'
A suitable constructor for type 'AspNetCore.Services.ServiceA' could not be located.
Ensure the type is concrete and services are registered for all parameters of a public constructor.

ASP.NET Core文档中所述 ,构造函数注入需要公共构造函数。

为什么是公共构造函数? 因为构造函数的默认可访问性级别为private。 DI是由ASP.NET Core实现的,除public外,它无法访问其他级别。

为什么不公开课? 因为DI 框架已经通过方法调用获取类。 如果我们要使用名称空间访问类,则需要public。

生命周期

当以下应用运行且没有任何请求到来时,是否将初始化单例服务?

public interface IServiceA { }

public class ServiceA : IServiceA
{
    public ServiceA ()
    {
        Console.WriteLine( "New SA" );
    }
}
public class Startup
{
    public void ConfigureServices ( IServiceCollection services )
    {
        services.AddSingleton<IServiceA, ServiceA>();
        ...
    }
}
public class HelloController : ControllerBase
{
    public WeatherForecastController ( IServiceA sa )
    {
        Console.WriteLine( $"Test Controller: {sa.GetHashCode()} " );
    }
}

ServiceA将不会初始化。 DI 框架 m将检查构造函数(我想),但不会初始化实例。 仅在使用单例服务时才会对其进行初始化。

在这种情况下,服务取决于控制器,并且控制器将针对每个请求进行初始化。 因此,作为单例服务,将在第一个请求到来时初始化ServiceA。 当第一个请求之后出现其他请求时,单例服务将不再初始化:

// 1st request
New SA
Test Controller: 83452835
// 2nd request
Test Controller: 83452835
// 3rd request
Test Controller: 83452835

如果我们使用AddScoped而不是AddSingleton,则DI框架将为每个请求初始化一个新实例。

// 1st request
New SA
Test Controller: 72334852
// 2nd request
New SA
Test Controller: 83729442
// 3rd request
New SA
Test Controller: 19231424

初始化顺序

如果我们按AB的顺序注入依赖关系,并按BA的顺序获取依赖关系,那么哪个将首先初始化?

public interface IServiceA { }
public class ServiceA : IServiceA
{
    public ServiceA ()
    {
        Console.WriteLine( "New SA" );
    }
}

public interface IServiceB { }
public class ServiceB : IServiceB
{
    public ServiceB ()
    {
        Console.WriteLine( "New SB" );
    }
}

public class Startup
{
    public void ConfigureServices ( IServiceCollection services )
    {
        services.AddSingleton<IServiceA, ServiceA>();
        services.AddSingleton<IServiceB, ServiceB>();
        ...
    }
}

public class HelloController : ControllerBase
{
    public WeatherForecastController ( IServiceB sb, IServiceA sa )
    {
        Console.WriteLine( $"Test Controller: {sa.GetHashCode()} " );
    }
}

结果:

New SB
New SA
Test Controller:83427434 22834295

尽管注入顺序是AB,但是因为我们先获取B,所以B将首先被初始化。

如果B依赖于A怎么办?

public class ServiceB : IServiceB
{
    public ServiceB ( IServiceA sa )
    {
        Console.WriteLine( $"New SB with sa: {sa.GetHashCode()} " );
    }
}

结果:

New SA
New SB with sa:46284926
Test Controller: 46284926 64753745

将首先初始化ServiceA,然后初始化ServiceB。 给定ServiceA是单例,将不会再次初始化。

如果我们在A之前注入B但B取决于A怎么办?

public void ConfigureServices ( IServiceCollection services )
{
    services.AddScoped<IServiceB, ServiceB>();
    services.AddScoped<IServiceA, ServiceA>();
}

结果:

New SA
New SB with sa:72362183
Test Controller: 72362183 91218567

注射顺序无关紧要。 DI容器将保留接口和Implement类之间的关系,并在初始化时为我们正确处理所有事情。

一接口多机具

如果有多个工具类并且都被注入,那么将初始化哪一个?

public interface IServiceA { }
public class ServiceA : IServiceA
{
    public ServiceA ()
    {
        Console.WriteLine( "New SA" );
    }
}
public class ServiceB : IServiceA
{
    public ServiceB ()
    {
        Console.WriteLine( "New SB" );
    }
}

public class Startup
{
    public void ConfigureServices ( IServiceCollection services )
    {
        services.AddSingleton<IServiceA, ServiceA>();
        services.AddSingleton<IServiceA, ServiceB>();
        ...
    }
}

public class HelloController : ControllerBase
{
    public WeatherForecastController ( IServiceA sa )
    {
        Console.WriteLine( $"Test Controller: {sa.GetHashCode()} " );
    }
}

结果:

New SB
Test Controller:46399782

仅最后一个将被初始化。 如果要第一个,请使用TryAdd。 如果给定的服务接口已经存在注册,则TryAdd将不起作用。

多接口一机具

如果有多个接口,并且只有一个实现类注册为单例,它将被初始化多少次?

public interface IServiceA { }
public interface IServiceB { }
public class ServiceB : IServiceA , IServiceB
{
    public ServiceB ()
    {
        Console.WriteLine( "New SB" );
    }
}

public class Startup
{
    public void ConfigureServices ( IServiceCollection services )
    {
        services.AddSingleton<IServiceA, ServiceB>();
        services.AddSingleton<IServiceB, ServiceB>();
        ...
    }
}

public class HelloController : ControllerBase
{
    public WeatherForecastController ( IServiceA sa, IServiceB sb )
    {
        Console.WriteLine( $"Test Controller: {sa.GetHashCode()} {sb.GetHashCode()} " );
    }
}

结果:

New SB
New SB
Test Controller:78346274

如您所见,“ AddSingleton”中的单例是指接口而不是工具。 ServicesB是两个接口的实现类,它们将分别初始化。

跟进

所有这些练习都是非常基本且通用的。 有些部分只是我个人的看法。 我是ASP.NET Core的初学者,如果您认为有任何问题,请更正。

如果您想了解有关ASP.NET Core中DI的更多信息,那么Microsoft.Extensions.DependencyInjection的源代码是不错的阅读方法。

参考资料

翻译自: https://hackernoon.com/exercises-on-dependency-injection-in-aspnet-introduction-lb173u6k

asp.net 依赖注入

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值