.NET6之MiniAPI(六):依赖注入

发布一下 0 0

在OOP里有依赖倒置原则 (The Dependency Inversion Principle),意思是 高层模块不应该依赖于底层模块,二者都应该依赖于抽象。换句话说,依赖于抽象,不要依赖于具体实现。

如下图,在完成订单后要调用快送模块,这时就依赖快递模块的接口,而不是具体的快递模块。



.NET6之MiniAPI(六):依赖注入

依赖关系注入 (Dependency Injection简称DI )

,是一种软件的设计模式,用来实现依赖之间的控制反转。asp.net core框架天生内置了这种技术。注入的地方称之为容器(与dcoker无关)或服务容器。

注入的时候可以分三种注入形态:

  • Transient
  • Scoped
  • Singleton

从字面意思也能了解,三种形态是访问的范围不同,通过Demo来看一下吧。

demo定义了TransientService,ScopedService,SingletonServie三个服务和它们对应的接口,分别在Service中实现了一个打印时间的Call方法。

三种Service和他们的实现

public interface ITransientService{    string Call();}public class TransientService : ITransientService{    public DateTime Time { get; init; } = DateTime.Now;    public string Call()    {        return $"TransientService {Time.ToString("yyyy-MM-dd HH:mm:ss.fffffff")} test……";    }}public interface IScopedService{    string Call();}public class ScopedService : IScopedService{    public DateTime Time { get; init; } = DateTime.Now;    public string Call()    {        return $"ScopedService {Time.ToString("yyyy-MM-dd HH:mm:ss.fffffff")} test……";          }}public interface ISingletonService{    string Call();}public class SingletonService : ISingletonService{    public DateTime Time { get; init; } = DateTime.Now;    public string Call()    {        return $"TSingletonService {Time.ToString("yyyy-MM-dd HH:mm:ss.fffffff")} test……";           }}

把三种服务和它们的接口注入到服务容器中, 为了使演示更清晰,增加了一个app.Use的方法,根据调用服务的url来判断是否是对应服务,然后调用Call方法,最后再调用Map到的方法,也就是说每次调用会有两个Call调用。

var builder = WebApplication.CreateBuilder();builder.Services.AddScoped<IScopedService, ScopedService>();builder.Services.AddTransient<ITransientService, TransientService>();builder.Services.AddSingleton<ISingletonService, SingletonService>();var app = builder.Build();app.Use(async (context, next) =>{    if (context.Request.Path.HasValue)    {        switch (context.Request.Path.Value)        {            case string s when s.Contains("transient"):                var transientService = context.RequestServices.GetService<ITransientService>();                Console.WriteLine($"--------------{transientService?.Call()}");                break;            case string s when s.Contains("scoped"):                var scopedService = context.RequestServices.GetService<IScopedService>();                Console.WriteLine($"--------------{scopedService?.Call()}");                break;            case string s when s.Contains("singleton"):                var singletonService = context.RequestServices.GetService<ISingletonService>();                Console.WriteLine($"--------------{singletonService?.Call()}");                break;        }    }    await next.Invoke();});app.MapGet("/transient", (ITransientService transientService) => transientService.Call());app.MapGet("/scoped", (IScopedService scopedService) => scopedService.Call());app.MapGet("/singleton", (ISingletonService singletonService) => singletonService.Call());app.Run();

看一下结果吧

ITransientService结果:两次调用皆不同

.NET6之MiniAPI(六):依赖注入

IScopedService结果:两次调用相同(一个http调用链路中都相同)

.NET6之MiniAPI(六):依赖注入

ISingletonService结果:每次调用相同

.NET6之MiniAPI(六):依赖注入

我画了一简单粗暴示意图如下:

.NET6之MiniAPI(六):依赖注入



多子类型注入

FedEx和UPS实现了IDelivery

class Order{    public decimal Amount { get; set; }}public interface IDelivery{    void Send();}public class FedEx : IDelivery{    public void Send()    {        Console.WriteLine("FedEx API");    }}public class UPS : IDelivery{    public void Send()    {        Console.WriteLine("UPS API");    }}

多次注入,用IEnumerable获取IDelivery,通过判断类型,获取想要IDelivery子类。

var builder = WebApplication.CreateBuilder();builder.Services.AddScoped<IDelivery, FedEx>();builder.Services.AddScoped<IDelivery, UPS>();var app = builder.Build();app.MapPost("/order", (IEnumerable<IDelivery> deliveries, Order order) =>{    //这里有一堆逻辑    if (order.Amount > 1000)    {        var fedEx = deliveries.SingleOrDefault(s => s is FedEx);        fedEx?.Send();    }    else    {        var usp = deliveries.SingleOrDefault(s => s is UPS);        usp?.Send();    }});app.Run();

版权声明:内容来源于互联网和用户投稿 如有侵权请联系删除

本文地址:http://0561fc.cn/70231.html