企业网站做推广,帮人做网站推选的公司,上海响应式网站建设公司,云表无代码开发平台ASP.NET Core框架建立在一个依赖注入框架之上#xff0c;已注入的方式消费服务已经成为了ASP.NET Core基本的编程模式。为了使读者能够更好地理解原生的注入框架框架#xff0c;我按照类似的设计创建了一个简易版本的依赖注入框架#xff0c;并它命名为“Cat”。本篇提供的四… ASP.NET Core框架建立在一个依赖注入框架之上已注入的方式消费服务已经成为了ASP.NET Core基本的编程模式。为了使读者能够更好地理解原生的注入框架框架我按照类似的设计创建了一个简易版本的依赖注入框架并它命名为“Cat”。本篇提供的四个实例主要体现了针对Cat的用法《一个Mini版的依赖注入框架》提供了针对设计和实现原理的介绍。[本文节选《ASP.NET Core 6框架揭秘》第2章][201]模拟容器Cat-普通服务的注册和提取源代码[202]模拟容器Cat-针对泛型服务类型的支持源代码[203]模拟容器Cat-为同一类型提供多个服务注册源代码[204]模拟容器Cat-服务实例的生命周期源代码[201]模拟容器Cat-普通服务的注册和提取我们定义了如下所示的接口和对应的实现类型来演示针对Cat的服务注册。Foo、Bar、Baz和Qux分别实现了对应的接口IFoo、IBar、IBaz和IQux其中Qux类型上标注的MapToAttribute特性注册了与对应接口IQux之间的映射。四个类型派生于的基类Base实现了IDisposable接口我们在其构造函数和实现的Dispose方法中输出相应的文本以确定对应的实例何时被创建和释放。我们还定义了一个泛型的接口IFoobarT1, T2和对应的实现类FoobarT1, T2用来演示Cat针对泛型服务实例的提供。public interface IFoo {}
public interface IBar {}
public interface IBaz {}
public interface IQux {}
public interface IFoobarT1, T2 {}public class Base : IDisposable
{public Base() Console.WriteLine($Instance of {GetType().Name} is created.);public void Dispose() Console.WriteLine($Instance of {GetType().Name} is disposed.);
}public class Foo : Base, IFoo{ }
public class Bar : Base, IBar{ }
public class Baz : Base, IBaz{ }
[MapTo(typeof(IQux), Lifetime.Root)]
public class Qux : Base, IQux { }
public class FoobarT1, T2: IFoobarT1,T2
{public T1 Foo { get; }public T2 Bar { get; }public Foobar(T1 foo, T2 bar){Foo foo;Bar bar;}
}Lifetime是一个代表服务实例生命周期的枚举它代表的三种生命周期模式定义如下。public enum Lifetime
{Root,Self,Transient
}如下所示的代码片段创建了一个Cat对象并采用上面提到的方式针对接口IFoo、IBar和IBaz注册了对应的服务它们采用的生命周期模式分别为Transient、Self和Root。另外我们还调用了另一个将当前入口程序集作为参数的Register方法该方法会解析指定程序集中标注了MapToAttribute特性的类型并进行批量服务注册。对于我们演示的程序来说该方法会完成针对IQux/Qux类型的服务注册。接下来我们利用Cat对象创建了它的两个子容器并调用子容器的GetServiceT方法来提供相应的服务实例。using App;var root new Cat().RegisterIFoo, Foo(Lifetime.Transient).RegisterIBar(_ new Bar(), Lifetime.Self).RegisterIBaz, Baz(Lifetime.Root).Register(typeof(Foo).Assembly);
var cat1 root.CreateChild();
var cat2 root.CreateChild();void GetServicesTService(Cat cat)
where TService : class
{cat.GetServiceTService();cat.GetServiceTService();
}GetServicesIFoo(cat1);
GetServicesIBar(cat1);
GetServicesIBaz(cat1);
GetServicesIQux(cat1);
Console.WriteLine();
GetServicesIFoo(cat2);
GetServicesIBar(cat2);
GetServicesIBaz(cat2);
GetServicesIQux(cat2);上面的程序运行之后会在控制台上输出图1所示的结果。由于服务IFoo被注册为Transient服务所以Cat针对四次请求都会创建一个全新的Foo对象。IBar服务的生命周期模式为Self对于同一个Cat只会创建一个Bar对象所以整个过程中会创建两个Bar对象。IBaz和IQux服务采用Root生命周期所以同根的两个Cat对象提供的其实是同一个Baz/Qux对象。图1Cat按照服务注册对应的生命周期模式提供服务实例[202]模拟容器Cat-针对泛型服务类型的支持Cat同样可以提供泛型服务实例。如下面的代码片段所示在为创建的Cat对象添加了针对IFoo和IBar接口的服务注册之后我们调用Register方法注册了针对泛型定义IFoobar,的服务注册具体的实现类型为Foobar,。当我们利用Cat对象提供一个类型为IFoobarIFoo, IBar的服务实例时它会创建并返回一个FoobarFoo, Bar对象。using App;using System.Diagnostics;var cat new Cat().RegisterIFoo, Foo(Lifetime.Transient).RegisterIBar, Bar(Lifetime.Transient) .Register(typeof(IFoobar,), typeof(Foobar,), Lifetime.Transient);
var foobar (FoobarIFoo, IBar?)cat.GetServiceIFoobarIFoo, IBar();
Debug.Assert(foobar?.Foo is Foo);
Debug.Assert(foobar?.Bar is Bar);[203]模拟容器Cat-为同一类型提供多个服务注册我们可以为同一个类型提供多个服务注册。虽然添加的所有服务注册均是有效的但由于GetServiceTService扩展方法总是返回一个服务实例我们对该方法应用了“后来居上”的策略即采用最近添加的服务注册创建服务实例。另一个GetServicesTService扩展方法将返回根据所有服务注册提供的服务实例。下面的代码片段为创建的Cat对象添加了三个针对Base类型的服务注册对应的实现类型分别为Foo、Bar和Baz。我们调用了Cat对象的GetServicesBase方法返回包含三个Base对象的集合集合元素的类型分别为Foo、Bar和Baz。using App;
using System.Diagnostics;var services new Cat().RegisterBase, Foo(Lifetime.Transient).RegisterBase, Bar(Lifetime.Transient).RegisterBase, Baz(Lifetime.Transient).GetServicesBase();
Debug.Assert(services.OfTypeFoo().Any());
Debug.Assert(services.OfTypeBar().Any());
Debug.Assert(services.OfTypeBaz().Any());[204]模拟容器Cat-服务实例的生命周期如果提供服务实例的类型实现了IDisposable接口我们必须在适当的时候调用其Dispose方法释放它。由于服务实例的生命周期完全由作为依赖注入容器的Cat对象来管理所以通过调用Dispose方法针对服务实例的释放也由它负责。Cat对象针对提供服务实例的释放策略取决于采用的生命周期模式具体的策略如下。Transient和Self所有实现了IDisposable接口的服务实例会被当前Cat对象保存起来当Cat对象自身的Dispose方法被调用的时候这些服务实例的Dispose方法会随之被调用。Root由于服务实例保存在作为根容器的Cat对象上所以当作为根的Cat对象的Dispose方法被调用的时候这些服务实例的Dispose方法会随之被调用。上述释放策略可以通过如下演示实例来印证。如下代码片段所示我们创建了一个Cat对象并添加了相应的服务注册。我们调用它的CreateChild方法创建了代表子容器的Cat对象并用它提供了四个注册服务对应的实例。using App;
using (var root new Cat().RegisterIFoo, Foo(Lifetime.Transient).RegisterIBar(_ new Bar(), Lifetime.Self).RegisterIBaz, Baz(Lifetime.Root).Register(typeof(IFoo).Assembly))
{ using (var cat root.CreateChild()){cat.GetServiceIFoo();cat.GetServiceIBar();cat.GetServiceIBaz();cat.GetServiceIQux();Console.WriteLine(Child cat is disposed.);}Console.WriteLine(Root cat is disposed.);
}由于两个Cat对象的创建都是在using块中进行的所以它们的Dispose方法都会在using块结束的地方被调用。该程序运行之后会在控制台上输出图2所示的结果我们可以看到当作为子容器的Cat对象的Dispose方法被调用时由它提供的两个生命周期模式分别为Transient和Self的服务实例Foo和Bar被正常释放。而生命周期模式为Root的服务实例Baz和Qux对象的Dispose方法会延迟到作为根容器的Cat对象的Dispose方法被调用的时候。图2 服务实例的释放《ASP.NET Core 6框架揭秘》实例演示[01]编程初体验《ASP.NET Core 6框架揭秘》实例演示[02]基于路由、MVC和gRPC的应用开发《ASP.NET Core 6框架揭秘》实例演示[03]Dapr初体验