本節學習利用第三方框架Autofac來增強容器能力,並引入面向切面(AOP)編程的概念。
那麼,先來了解一下
什麼時候需要引入第三方容器組件呢?
-
基於名稱的注入
-
屬性注入
-
子容器
-
基於動態代理的AOP
核心擴展點
public interface IServiceProviderFactory<TContainerBuilder>
第三方的擴展框架都是基於這個接口做擴展的
Autofac擴展包
-
Autofac.Extensions.DependencyInjection
-
Autofac.Extras.DynamicProxy
下面,我們就通過代碼來演示如何使用Autofac以及使用Autofac來實現上述幾種情況。
代碼演示
首先說一下,代碼架構,這裏主要是定義了一個接口,然後定義了2個實現該接口的類,其中第二個類包含一個屬性,用於驗證屬性注入。類的代碼如下
public interface IMyService
{
void show();
}
public class MyService : IMyService
{
public void show()
{
Console.WriteLine($"this is MyService.show,{GetHashCode()}");
}
}
public class MyServiceV2 : IMyService
{
public MyNameService myNameService { get; set; }
public void show()
{
Console.WriteLine($"this is MyServiceV2.show,{GetHashCode()},MyNameService是否爲空:{myNameService==null}");
}
}
public class MyNameService { }
Autofac使用步驟
1.註冊第三方組件入口
在使用第三方組件時,我們需要先通過配置來啓用第三方組件,如下,我們在CreateHostBuilder中添加如下語句。
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
2.服務註冊入口
組件入口註冊後,我們需要定義第三方組件自己的服務註冊入口,我們可以在startup裏新增一個ConfigureContainer方法來實現,方法入參是Autofac.ContainerBuilder,其實,這裏我們的服務註冊進默認的容器後,會被Autofac接替,然後執行ConfigureContainer.
public void ConfigureContainer(ContainerBuilder containerBuilder)
{
//...
}
3.接收Autofac的容器
之後,我們需要創建一個作用域,用於在根容器內接收Autofac的容器對象。
public ILifetimeScope AutofacContainer { get; private set; }
//根容器獲取
this.AutofacContainer = app.ApplicationServices.GetAutofacRoot();
到這裏,我們就完成了所有的準備步驟,可以開始上述幾種場景的演示了。
常規注入
在這之前,我們先了解一下常規注入方式以及獲取方式,這裏注意一下,Autofac的注入方式是先注入服務在指定其類型。如下
//常規註冊
containerBuilder.RegisterType<MyService>();//未指定類型,通過IMyService不能獲取
containerBuilder.RegisterType<MyService>().As<IMyService>();
containerBuilder.RegisterType<MyServiceV2>().As<IMyService>();
獲取方式如下
var service = this.AutofacContainer.Resolve<IMyService>();
Autofac的服務獲取方式是一組以Resolve...開頭的方法,比如,下面要說的命名服務的獲取方式可通過ResolveNamed方法獲取。
基於名稱的注入及獲取
//註冊
containerBuilder.RegisterType<MyService>().Named<IMyService>("myService");
//獲取
IMyService myService = this.AutofacContainer.ResolveNamed<IMyService>("myService");
屬性注入
屬性注通過PropertiesAutowired來開啓屬性注入,在屬性注入前要先註冊要注入的服務
//注入要注入的服務
containerBuilder.RegisterType<MyNameService>();
//開啓屬性注入
containerBuilder.RegisterType<MyServiceV2>().As<IMyService>().PropertiesAutowired();
AOP編程
Autofac提供了一個IInterceptor的接口,用於提供AOP的能力,我們可以通過實現該接口,將一些特定的邏輯嵌入到方法的切面中,並控制是否執行原有代碼邏輯,一般,我們稱該類爲攔截器,如下,是一個攔截器示例
public class Interceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.WriteLine($"{invocation.Method.Name}執行前");
//不調用該方法,可禁用原有邏輯
invocation.Proceed();
Console.WriteLine($"{invocation.Method.Name}執行後");
}
}
那麼,如何開啓攔截器呢?主要有以下幾步
-
注入攔截器
-
通過InterceptedBy來定義允許的類型
-
開啓攔截器開關,分爲類攔截器和接口攔截器(常用)
代碼如下:
//注入攔截器
containerBuilder.RegisterType<Interceptor>();
//定義允許的類型並開啓攔截器
containerBuilder.RegisterType<MyService>().As<IMyService>().InterceptedBy(typeof(Interceptor)).EnableInterfaceInterceptors();
子容器
我們知道,通過Scope可以創建子容器,在Autofac中,可以通過InstancePerMatchingLifetimeScope來創建特定名稱的子容器,一般使用在期望某一服務不在根容器創建,但又希望它在一定的範圍內是單例的情況下。
containerBuilder.RegisterType<MyServiceV2>().InstancePerMatchingLifetimeScope("myscope");
也可以通過如下代碼來驗證容器是否是單例
using (var myscope = AutofacContainer.BeginLifetimeScope("myscope"))
{
var service0 = myscope.Resolve<MyServiceV2>();
using (var scope = myscope.BeginLifetimeScope())
{
var service1 = myscope.Resolve<MyServiceV2>();
var service2 = myscope.Resolve<MyServiceV2>();
Console.WriteLine($"service1==service2?{service1 == service2}");
Console.WriteLine($"service1==service2?{service0 == service1}");
}
}
本節到此就要結束了,從下節將開始配置框架的學習。
源碼可訪問
https://github.com/IronMarmot/Samples/tree/master/CoreSamples
更多課程詳細內容,可識別下方二維碼購買。
【掃描二維碼購買課程,可後臺留言獲得10元紅包返現。】
部分內容來源於網絡,侵刪。
更多精彩內容,請微信搜索攻城獅客棧 或掃描下方二維碼
------------------------------------------------------------------------------
公衆號:攻城獅客棧
CSDN:畫雞蛋的不止達芬奇
讓我們一起變的更優秀。