首页 > 编程语言 >asp.net core之依赖注入

asp.net core之依赖注入

时间:2023-07-25 15:11:06浏览次数:52  
标签:core asp 服务 public 实例 单例 net Id 注入

依赖注入概念

ASP.NET Core 支持依赖关系注入 (DI) 软件设计模式,这是一种在类及其依赖关系之间实现控制反转 (IoC) 的技术。
按照官方文档的描述:
依赖关系注入通过以下方式解决了这些问题:

  • 使用接口或基类将依赖关系实现抽象化。
  • 在服务容器中注册依赖关系。 ASP.NET Core 提供了一个内置的服务容器 IServiceProvider。 服务通常已在应用的 Program.cs 文件中注册。
  • 将服务注入到使用它的类的构造函数中。 框架负责创建依赖关系的实例,并在不再需要时将其释放。

探索Asp.net core中的依赖注入

生命周期

在asp.net core中,以来注入有三个生命周期。
分别为Singleton(单例),Scoped(范围),Transient(瞬态)。
Singleton(单例),很好理解,就是一个单例模式,在整个应用的生命周期中只会初始化一次。
Scoped(范围),每一次请求中实例化一次。
Transient(瞬态),每次使用都是一个新的实例化对象。
注入方式分别如下:

services.AddSingleton(); //单例
services.AddScoped(); //范围
services.AddTransient(); //瞬态

来实践一下,用VS新建一个WebApi项目,然后添加三个类,对应三个生命周期。

public class TestTransient
{
    public TestTransient()
    {
        Id = Guid.NewGuid();
    }

    public Guid Id { get; set; }
}
public class TestSingleton
{
    public TestSingleton()
    {
        Id = Guid.NewGuid();
    }

    public Guid Id { get; set; }
}
public class TestScoped
{
    public TestScoped()
    {
        Id = Guid.NewGuid();
    }

    public Guid Id { get; set; }
}

然后在Program中添加注入,这里我没用接口注入,直接注入类,我们也可以使用接口注入的方式。

builder.Services.AddSingleton<TestSingleton>();
builder.Services.AddScoped<TestScoped>();
builder.Services.AddTransient<TestTransient>();

接下来我们在控制器中通过构造函数注入我们的三个类。

private readonly ILogger<WeatherForecastController> _logger;
private readonly TestScoped _testScoped;
private readonly TestSingleton _testSingleton;
private readonly TestTransient _testTransient;

public WeatherForecastController(ILogger<WeatherForecastController> logger, TestScoped testScoped, TestSingleton testSingleton, TestTransient testTransient)
{
    _logger = logger;
    _testScoped = testScoped;
    _testSingleton = testSingleton;
    _testTransient = testTransient;
}

在调用Get方法中打印我们的Id
第一次请求
image.png
第二第三次请求
image.png
可以看到单例的Id每次请求都是一致的,而范围和瞬态的在不同请求中都不一样。
那么如何区别Scoped和Transient呢?很简单,我们直接整一个简单的中间件,分别注入并答应对应Id。

app.Use(async (httpContext, next) => 
{
    var scoped = httpContext.RequestServices.GetRequiredService<TestScoped>();
    var transient = httpContext.RequestServices.GetRequiredService<TestTransient>();
    Console.WriteLine($"Middleware scoped: {scoped.Id}");
    Console.WriteLine($"Middleware transient: {transient.Id}");
    await next(httpContext);
});

image.png
可以看到,在一次请求中Scoped的Id是一致的,Transient的Id每次都不一样。

服务注册方法

在上面中我只是用了其中一种注册方法,就是直接注册类。
除此之外,我们还可以通过接口注入。
比如我们添加一个IScopedDependency的接口,然后新建一个TestAbcScoped继承IScopedDependency,然后在Program中添加注入

builder.Services.AddScoped<IScopedDependency, TestAbcScoped>();

之后我们在构造器中使用IScopedDependency注入的话,则自动会获得TestAbcScoped的实现实例。
image.png
通过我们Debug监视,可以发现IScopedDependency注入的实例确实是TestAbcScoped。
当我们注册同一个接口的多个实现时,默认取最后一次注入的实例,当我们需要获取全部接口的实现时,可以通过注入IEnumerable获取该接口的所有实现。
我们增加一个IScopedDependency的实现

public class TestAbcScoped : IScopedDependency
{
}
public class TestAbcdScoped : IScopedDependency
{
}

注册顺序为:

builder.Services.AddScoped<IScopedDependency, TestAbcScoped>();
builder.Services.AddScoped<IScopedDependency, TestAbcdScoped>();

image.png
可以看到,单个注入会取后注入的实例,IEnumerable注入则会获取所有的实例。
注意:
除此之外,还有TryAddXXX的方法,注册服务时,如果还没有添加相同类型的实例,就添加一个实例。
服务注册通常与顺序无关,除了注册同一类型的多个实现时。

服务注入

上面我们实操时所用的注入方法都是构造器注入,这也是官方推荐的注入方式。
除此之外,我们还可以使用IServiceProvider获取服务,上面中间件所用到的HttpContext.RequestService本质是一个IServiceProvider实例。
三方框架加持注入功能,asp.net core的注入方式有限,我们可以使用Autofac来增强。
使用autofac之后我们可以支持属性注入,即无需在构造器中添加,只需要构造对应的属性即可。
属性注入和构造器注入的优缺点对比。
构造器注入可以清晰的看出我们所有注入的实例,对于协作和沟通有比较大的帮助。但是,若是注入的东西太多,会导致一个很庞大的构造器,当然官方的建议是,当存在那么多的注入的时候,就需要考虑拆分业务了。
属性注入则只需要通过构造一个属性,系统自动注入,弱点是没有构造器清晰辨别。毕竟不容易区分哪些属性是通过注入的,哪些是业务赋值的。
在考虑到继承方面时,有时候属性注入会比构造器注入合适,比如在基类中,我们往往可以注入通用的服务,这样在子类的构造器中就无需再次注入该服务。

注意事项

在使用依赖注入的时候,我们最好要明确每个服务的生命周期,在长生命周期的服务中,切勿注入短生命周期的服务。
如在单例中注入范围服务或瞬时服务,在范围服务中注入瞬时服务。否则会出现对象已被释放的情况。
在新版本中,单例里面注入范围服务,程序会自动检测并提示异常。但是在旧版本中是没有提示的,这点需要注意。
image.png

如何在单例中使用Scoped范围服务呢,可以使用IServiceScopeFactory,IServiceScopeFactory始终注册为单例实例,通过IServiceScopeFactory创建一个Scope生命周期。

public class TestSingleton
{
    private readonly IServiceScopeFactory _serviceScopeFactory;
    public TestSingleton(IServiceScopeFactory serviceScopeFactory)
    {
        _serviceScopeFactory = serviceScopeFactory;
        Id = Guid.NewGuid();
    }

    public Guid Id { get; set; }

    public void Console()
    {
        using(var scope = _serviceScopeFactory.CreateScope()) 
        {
            var testScoped = scope.ServiceProvider.GetRequiredService<TestScoped>();
            System.Console.WriteLine($"TestSingleton - TestScoped: {testScoped.Id}");
        }
    }
}

再次启动服务正常,并且请求可以看到,我们CreateScope后,生成的Id也是跟请求中的Scoped不一样的,因为他们属于不同的Scoped。
image.png

欢迎进群催更。

标签:core,asp,服务,public,实例,单例,net,Id,注入
From: https://www.cnblogs.com/fanshaoO/p/17579976.html

相关文章

  • .Net 项目类型区别 Windows窗体应用程序
    .NET框架(特定于Windows),然后使用WindowsFormsApp(.NETFramework)。Windows窗体应用程序(.NETFramework) 解决方案默认名称:windowsFormsApp.NET核心/.NET(跨平台),然后使用WindowsFormsApp。Windows窗体应用程序  解决方案默认名称:winFormsApp......
  • 通过iptables转发后的端口telnet通但是curl不通的问题
    今天遇到一个问题,一个隔离安全域的服务器需要访问承载网上的gitlab,但是无法直接做互通,所以需要通过iptables转发一次。完成iptables规则后,发现telnet端口是通的但是curlhttp:地址加端口就会返回不通。于是不停的改iptables规则,甚至放行forword规则,最后检查发现是存在外网的代理(代......
  • Kubernetes修改Pod数量
    修改kubeletpod数量并在启动命令尾部添加变量$KUBELET_NODE_MAX_PODS如下:重启kubelet:[root@k8s02~]#systemctldaemon-reload&&systemctlrestartkubelet检查结果:[root@k8s02~]#kubectldescribenodek8s02|greppodspods:150pods:......
  • .NET(C#) 设计模式
    .NET(C#)设计模式简介设计模式(Designpattern)是代码设计经验的总结。设计模式主要分三个类型:创建型、结构型和行为型。创建型是对象实例化的模式,创建型模式用于解耦对象的实例化过程,主要用于创建对象。结构型是把类或对象结合在一起形成一个更大的结构,主要用于优化不同类、对......
  • calico报错son: cannot unmarshal string into Go struct field NetConf.mtu of type
     于是describe查看宿主机的配置文件查看日志没有相关日志查看calico的相关配置文件值找到于是想着直接去修改calico的Configmap发现修改不成功便去查询宿主机映射的calico挂载文件把标记部分的string给成int去掉双引号,然后重启calico然后通过ansible分发到每台机器上an......
  • NetCore 控制台 上下文 注入 dbcontext
    publicclassProgram{privatestaticTestDBContext_tContext;privatestaticvoidMain(string[]args){Startup();vardd=_tContext.User.Take(1).ToList();//e();}privatestaticvoidStartup()......
  • RDIFramework.NET CS敏捷开发框架 V6.0发布(支持.NET6+、Framework双引擎可选,全网唯一
    全新RDIFramework.NETV6.0CS敏捷开发框架发布,全网唯一支持.NET6+,Framework双引擎,降低开发成本,提高产品质量,提升用户体验与开发团队稳定性,做软件就选RDIFramework.NET敏捷开发框架。1、RDIFramework.NETCS敏捷开发框架介绍RDIFramework.NETC/S敏捷开发框架,是我司重磅推出......
  • 论文解读|用于从RGB-D数据进行3D物体检测的Frustum PointNets
    原创|文BFT机器人01摘要论文研究了室内和室外场景中基于RGBD数据的3D目标检测。论文的方法不仅仅依赖于3D方案,而是利用成熟的2D对象检测器和先进的3D深度学习进行对象定位,即使是小对象也能实现高效率和高召回。直接在原始点云中学习,可以在强遮挡或非常稀疏的点下也能够精确地估......
  • 特征选择 - Fisher Score
    特征选择的目的在理想情况下,特征选择想要达到以下效果:简化模型以提高可解释性:通过减少特征的数量,模型变得更简单,更容易理解。这对于那些需要理解模型如何做出预测的领域(如医疗或信贷评分)非常重要。改进模型性能:通过消除无关或冗余的特征,模型的预测性能可能会得到提高。这是......
  • Authentication in asp.net core异常汇总
     services.AddAuthentication("Microsoft")      .AddMicrosoftIdentityWebApp(Configuration,"AzureAd","Microsoft");InvalidOperationException:Nosign-outauthenticationhandlerisregisteredforthescheme'OpenIdCon......