C# Autofac的具體使用
一、為什么使用Autofac?
Autofac是.NET領(lǐng)域最為流行的IoC框架之一,傳說是速度最快的一個。
1.1、性能
有人專門做了測試:


1.2、優(yōu)點
1)與C#語言聯(lián)系很緊密。C#里的很多編程方式都可以為Autofac使用,例如可以使用Lambda表達(dá)式注冊組件。
2)較低的學(xué)習(xí)曲線。學(xué)習(xí)它非常的簡單,只要你理解了IoC和DI的概念以及在何時需要使用它們。
3)支持JSON/XML配置。
4)自動裝配。
5)與Asp.Net MVC集成。
6)微軟的Orchad開源程序使用的就是Autofac,可以看出它的方便和強大。
1.3、資源
- 官方網(wǎng)站:http://autofac.org/
- GitHub網(wǎng)址:https://github.com/autofac/Autofac
- 學(xué)習(xí)資料:Autofac中文文檔
二、數(shù)據(jù)準(zhǔn)備
2.1、新建項目(例)
| 項目名稱 | 項目說明 | 輸出類型 | 引用項目(簡寫) |
|---|---|---|---|
| AlXiao.IService | 接口 | 類庫 | |
| AlXiao.Service | 接口實現(xiàn) | 類庫 | IService |
| AlXiao.AdminWebApi | 客戶端 | .NETWebApi | IService、Service |
IService下的接口類:
namespace AlXiao.IService
{
public interface IAccountService
{
/// <summary>
/// 后臺程序登陸
/// </summary>
/// <param name="UserRequest">后臺用戶信息</param>
/// <returns></returns>
Task<ResponseResult> LoginByWeb(tb_adminuser_request UserRequest);
}
}
Service下的接口實現(xiàn)類:
namespace AlXiao.Service
{
public class AccountService: IAccountService
{
/// <summary>
/// 后臺程序登陸
/// </summary>
/// <param name="UserRequest">后臺用戶信息</param>
/// <returns></returns>
public async Task<ResponseResult> LoginByWeb(tb_adminuser_request UserRequest)
{
try
{
//自己寫登錄功能
}
catch (Exception ex)
{
}
}
}
}
namespace AlXiao.Service
{
public class AccountService2: IAccountService
{
/// <summary>
/// 后臺程序登陸
/// </summary>
/// <param name="UserRequest">后臺用戶信息</param>
/// <returns></returns>
public async Task<ResponseResult> LoginByWeb(tb_adminuser_request UserRequest)
{
try
{
//自己寫登錄功能
}
catch (Exception ex)
{
}
}
}
}
2.2、Autofac安裝
Client項目右鍵->管理 NuGet 程序包->Autofac

三、IoC-注冊
3.1、類型注冊
a)類型注冊:使用RegisterType進(jìn)行注冊
/注冊Autofac組件 ContainerBuilder builder = new ContainerBuilder; //注冊實現(xiàn)類AccountService,當(dāng)我們請求IAccountService接口的時候,返回的是類Student的對象。 builder.RegisterType<AccountService>.As<IAccountService> ; //上面這句也可改成下面這句,這樣請求AccountService實現(xiàn)了的任何接口的時候,都會返回AccountService對象。 //builder.RegisterType<AccountService>.AsImplementedInterfaces(); IContainer container = builder.Build; //請求IAccountService接口 IAccountService baseAccount= container.Resolve<IAccountService> ; baseAccount.LoginByWeb(model);
b)類型注冊(別名):假如一個接口有多個實現(xiàn)類,可以在注冊時起別名。
ContainerBuilder builder = newContainerBuilder; builder.RegisterType <AccountService>.Named<IAccountService>( "S1"); builder.RegisterType <AccountService2>.Named<IAccountService>( "S2"); IContainer container = builder.Build; var s1= container.ResolveNamed<IAccountService >( "S1"); s1.LoginByWeb(model); var s2 = container.ResolveNamed<IAccountService >( "S2"); s2.LoginByWeb(model);
c)類型注冊(枚舉):假如一個接口有多個實現(xiàn)類,也可以使用枚舉的方式注冊。
public enum ServiceType
{
AccountService,
AccountService2
}
ContainerBuilder builder = new ContainerBuilder;
builder.RegisterType <AccountService>.Keyed<IAccountService> (ServiceType.AccountService);
builder.RegisterType <AccountService2>.Keyed<IAccountService> (ServiceType.AccountService2);
IContainer container = builder.Build;
var s1= container.ResolveKeyed<IAccountService> (ServiceType.AccountService);
s1.LoginByWeb(model);
var s2= container.ResolveKeyed<IAccountService> (ServiceType.AccountService2);
s2.LoginByWeb(model);
3.2、實例注冊
ContainerBuilder builder = newContainerBuilder; builder.RegisterInstance <IAccountService>( new AccountService); IContainer container = builder.Build; IAccountService baseAccount= container.Resolve<IAccountService> ; baseAccount.LoginByWeb(model);
3.3、Lambda注冊
a)Lambda注冊
ContainerBuilder builder = newContainerBuilder; builder.Register(c => new AccountService).As<IAccountService> ; IContainer container = builder.Build; IAccountService baseAccount= container.Resolve<IAccountService> ; baseAccount.LoginByWeb(model);
b)Lambda注冊(NamedParameter)
ContainerBuilder builder = newContainerBuilder;
builder.Register<IAccountService>((c, p) =>
{
vartype = p.Named<string>("type");
if (type == "S1")
{
return new AccountService;
}
else
{
return new AccountService2;
}
}).As<IAccountService>;
IContainer container = builder.Build;
var s1= container.Resolve<IAccountService>(newNamedParameter("type", "S1"));
s1.LoginByWeb(model);
3.4、程序集注冊
如果有很多接口及實現(xiàn)類,假如覺得這種一一注冊很麻煩的話,可以一次性全部注冊,當(dāng)然也可以加篩選條件。
ContainerBuilder builder = newContainerBuilder;
Assembly assembly = Assembly.Load( "AlXiao.IService"); //實現(xiàn)類所在的程序集名稱
builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces; //常用
//builder.RegisterAssemblyTypes(assembly).Where(t=>t.Name.StartsWith("Service")).AsImplementedInterfaces; //帶篩選
//builder.RegisterAssemblyTypes(assembly).Except<School>.AsImplementedInterfaces; //帶篩選
IContainer container = builder.Build;
//單實現(xiàn)類的用法
IAccountService baseAccount= container.Resolve<IAccountService> ;
baseAccount.LoginByWeb(model);
//多實現(xiàn)類的用法
IEnumerable<IAccountService> list= container.Resolve<IEnumerable<IAccountService>> ;
foreach( var item in list)
{
item.LoginByWeb(model);
}
3.5、泛型注冊
ContainerBuilder builder = new ContainerBuilder; builder.RegisterGeneric(typeof(List<>)).As( typeof(IList<> )); IContainer container = builder.Build; IList <string> list = container.Resolve<IList<string>>;
3.6、默認(rèn)注冊
ContainerBuilder builder = new ContainerBuilder; //對于同一個接口,后面注冊的實現(xiàn)會覆蓋之前的實現(xiàn)。 //如果不想覆蓋的話,可以用PreserveExistingDefaults,這樣會保留原來注冊的實現(xiàn)。 builder.RegisterType<AccountService>.As<IAccountService> ; builder.RegisterType <AccountService1>.As<IAccountService>.PreserveExistingDefaults; //指定為非默認(rèn)值 IContainer container = builder.Build; var s1= container.Resolve<IAccountService> ; s1.LoginByWeb(model);
四、IoC-注入
4.1、構(gòu)造函數(shù)注入
ContainerBuilder builder = new ContainerBuilder; builder.RegisterType <AccountService> ; builder.RegisterType <AccountService1>.As<IAccountService> ; IContainer container = builder.Build; AccountService s1= container.Resolve<AccountService> ; s1.LoginByWeb(model);
4.2、屬性注入
ContainerBuilder builder = new ContainerBuilder; Assembly assembly = Assembly.Load( "AlXiao.IService"); //實現(xiàn)類所在的程序集名稱 builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces.PropertiesAutowired; //常用 IContainer container = builder.Build; IAccountService s1= container.Resolve<IAccountService> ; s1.LoginByWeb(model);
五、IOC-事件
Autofac在組件生命周期的不同階段,共對應(yīng)了5個事件,執(zhí)行順序如下所示:
1.OnRegistered->2.OnPreparing->3.OnActivating->4.OnActivated->5.OnRelease
ContainerBuilder builder = new ContainerBuilder;
builder.RegisterType <AccountService>.As<IAccountService>
.OnRegistered(e => Console.WriteLine( "OnRegistered:在注冊的時候調(diào)用"))
.OnPreparing(e => Console.WriteLine( "OnPreparing:在準(zhǔn)備創(chuàng)建的時候調(diào)用"))
.OnActivating(e => Console.WriteLine( "OnActivating:在創(chuàng)建之前調(diào)用"))
//.OnActivating(e => e.ReplaceInstance(new Student("1000", "Test")))
.OnActivated(e => Console.WriteLine( "OnActivated:在創(chuàng)建之后調(diào)用"))
.OnRelease(e => Console.WriteLine( "OnRelease:在釋放占用的資源之前調(diào)用"));
using(IContainer container = builder.Build)
{
IAccountService s1= container.Resolve<IAccountService> ;
s1.LoginByWeb(model);
}
六、IoC-生命周期
6.1、Per Dependency
Per Dependency:為默認(rèn)的生命周期,也被稱為"transient"或"factory",其實就是每次請求都創(chuàng)建一個新的對象。
ContainerBuilder builder = new ContainerBuilder; Assembly assembly = Assembly.Load( "AlXiao.IService"); //實現(xiàn)類所在的程序集名稱 builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces.PropertiesAutowired.InstancePerDependency; //常用 IContainer container = builder.Build; IAccountService s1= container.Resolve<IAccountService> ; IAccountService s2 = container.Resolve<IAccountService> ; return s1.Equals(s2);
6.2、Single Instance
Single Instance:就是每次都用同一個對象。
ContainerBuilder builder = new ContainerBuilder; Assembly assembly = Assembly.Load( "AlXiao.IService"); //實現(xiàn)類所在的程序集名稱 builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces.PropertiesAutowired.SingleInstance; //常用 IContainer container = builder.Build; IAccountService s1= container.Resolve<IAccountService> ; IAccountService s2= container.Resolve<IAccountService> ; return ReferenceEquals(s1, s2);
6.3、Per Lifetime Scope
Per Lifetime Scope:同一個Lifetime生成的對象是同一個實例。
ContainerBuilder builder = new ContainerBuilder;
builder.RegisterType <AccountService>.As<IAccountService> .InstancePerLifetimeScope;
IContainer container = builder.Build;
IAccountService s1= container.Resolve<IAccountService> ;
IAccountService s2 = container.Resolve<IAccountService> ;
Console.WriteLine(s1.Equals(s2));
using(ILifetimeScope lifetime = container.BeginLifetimeScope)
{
IAccountService s3 = lifetime.Resolve<IAccountService> ;
IAccountService s4 = lifetime.Resolve<IAccountService> ;
Console.WriteLine(s3.Equals(s4));
Console.WriteLine(s2.Equals(s3));
}
七、IoC-通過配置文件使用Autofac
7.1、組件安裝
Client項目右鍵->管理 NuGet 程序包->Autofac.Configuration及Microsoft.Extensions.Configuration.Xml。


7.2、配置文件
新建一個AutofacConfigIoC.xml文件,在其屬性的復(fù)制到輸出目錄項下選擇始終復(fù)制。
<?xml version="1.0" encoding="utf-8" ?> <autofac defaultAssembly="AlXiao.IService"> <!--無注入--> <components name="1001"> <type>AlXiao.IService.AccountService, AlXiao.IService </type> <services name="0"type="AlXiao.IService.IAccountService"/> <injectProperties>true </injectProperties> </components> <components name="1002"> <type>AlXiao.IService.AccountService, AlXiao.IService</type> <services name="0"type="AlXiao.IService.IAccountService2"/> <injectProperties>true </injectProperties> </components> <!--構(gòu)造函數(shù)注入--> <components name="2001"> <type>AlXiao.IService.AccountService, AlXiao.IService</type> <services name="0"type="AlXiao.IService.AccountService, AlXiao.IService"/> <injectProperties>true </injectProperties> </components> <!--屬性注入--> <components name="3001"> <type>AlXiao.IService.AccountService, AlXiao.IService</type> <services name="0"type="AlXiao.IService.IAccountService"/> <injectProperties>true </injectProperties> </components> </autofac>
7.3、測試代碼
//加載配置 ContainerBuilder builder = new ContainerBuilder; varconfig = new ConfigurationBuilder; config.AddXmlFile( "AutofacConfigIoC.xml"); varmodule = newConfigurationModule(config.Build); builder.RegisterModule(module); IContainer container = builder.Build; //無注入測試 IAccountService s = container.Resolve<IAccountService> ; s.LoginByWeb(model); //構(gòu)造函數(shù)注入測試 AccountService s= container.Resolve<AccountService> ; s.LoginByWeb(model); //屬性注入測試 IAccountService s= container.Resolve<IAccountService> ; s.LoginByWeb(model);
八、AOP
8.1、組件安裝
Client項目右鍵->管理 NuGet 程序包->Autofac.Extras.DynamicProxy。

8.2、拉截器
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Castle.DynamicProxy;
namespace AlXiao.CommonCore.DTO
{
///<summary>
///攔截器:需實現(xiàn)IInterceptor接口。
///</summary>
public class CallLogger : IInterceptor
{
private readonly TextWriter _output;
public CallLogger(TextWriter output)
{
_output = output;
}
///<summary>
///攔截方法:打印被攔截的方法--執(zhí)行前的名稱、參數(shù)以及執(zhí)行后的返回結(jié)果。
///</summary>
///<param name="invocation">被攔截方法的信息</param>
public void Intercept(IInvocation invocation)
{
//空白行
_output.WriteLine;
//在下一個攔截器或目標(biāo)方法處理之前的處理
_output.WriteLine($ "調(diào)用方法:{invocation.Method.Name}");
if (invocation.Arguments.Length > 0)
{
_output.WriteLine($ "參數(shù):{string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString).ToArray)}");
}
//調(diào)用下一個攔截器(若存在),直到最終的目標(biāo)方法(Target Method)。
invocation.Proceed;
//獲取被代理方法的返回類型
varreturnType = invocation.Method.ReturnType;
//異步方法
if (IsAsyncMethod(invocation.Method))
{
//Task:返回值是固定類型
if (returnType != null && returnType == typeof(Task))
{
//定義一個異步方法來等待目標(biāo)方法返回的Task
asyncTask Continuation => await(Task)invocation.ReturnValue;
//Continuation中并沒有使用await,所以Continuation就如同步方法一樣是阻塞的。
invocation.ReturnValue = Continuation;
}
//Task<T>:返回值是泛型類型
else
{
//獲取被代理方法的返回類型
varreturnTypeT = invocation.Method.ReflectedType;
if (returnTypeT != null)
{
//獲取泛型參數(shù)集合,集合中的第一個元素等價于typeof(Class)。
varresultType = invocation.Method.ReturnType.GetGenericArguments[0];
//利用反射獲得等待返回值的異步方法
MethodInfo methodInfo = typeof(CallLogger).GetMethod("HandleAsync", BindingFlags.Public | BindingFlags.Instance);
//調(diào)用methodInfo類的MakeGenericMethod方法,用獲得的類型T(<resultType>)來重新構(gòu)造HandleAsync方法。
varmi = methodInfo.MakeGenericMethod(resultType);
//Invoke:使用指定參數(shù)調(diào)用由當(dāng)前實例表示的方法或構(gòu)造函數(shù)。
invocation.ReturnValue = mi.Invoke(this, new[] { invocation.ReturnValue });
}
}
vartype = invocation.Method.ReturnType;
varresultProperty = type.GetProperty("Result");
if (resultProperty != null)
_output.WriteLine($ "方法結(jié)果:{resultProperty.GetValue(invocation.ReturnValue)}");
}
//同步方法
else
{
if (returnType != null && returnType != typeof(void))
_output.WriteLine($ "方法結(jié)果:{invocation.ReturnValue}");
}
}
///<summary>
///判斷是否異步方法
///</summary>
public static bool IsAsyncMethod(MethodInfo method)
{
return
(
method.ReturnType == typeof(Task) ||
(method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition == typeof(Task<>))
);
}
///<summary>
///構(gòu)造等待返回值的異步方法
///</summary>
///<typeparam name="T"></typeparam>
///<param name="task"></param>
///<returns></returns>
public async Task<T> HandleAsync<T>(Task<T> task)
{
vart = awaittask;
returnt;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Castle.DynamicProxy;
namespace AlXiao.CommonCore.DTO
{
public class CallTester : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.WriteLine("啥也不干");
invocation.Proceed;
Console.WriteLine("也不干啥");
}
}
}
8.3、測試代碼
注意:對于以類方式的注入,Autofac Interceptor要求類的方法必須為virtual方法。如AnimalWagging類的Wagging、WaggingAsync(string name)都加了virtual修飾符
ContainerBuilder builder = new ContainerBuilder;
//注冊攔截器
builder.Register(c => newCallLogger(Console.Out));
builder.Register(c => new CallTester);
//動態(tài)注入攔截器
//這里定義了兩個攔截器,注意它們的順序。
builder.RegisterType<Student>.As<IStudent>.InterceptedBy( typeof(CallLogger), typeof(CallTester)).EnableInterfaceInterceptors;
//這里定義了一個攔截器
builder.RegisterType<AnimalWagging>.InterceptedBy( typeof(CallLogger)).EnableClassInterceptors;
builder.RegisterType <Dog>.As<IAnimalBark> ;
IContainer container = builder.Build;
IStudent student = container.Resolve<IStudent> ;
student.Add( "1003", "Kobe");
AnimalWagging animal = container.Resolve<AnimalWagging> ;
animal.Wagging;
Task <string> task = animal.WaggingAsync( "哈士奇");
Console.WriteLine($ "{task.Result}");到此這篇關(guān)于C# Autofac的具體使用的文章就介紹到這了,更多相關(guān)C# Autofac內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#多態(tài)的三種實現(xiàn)方式(小結(jié))
這篇文章主要介紹了C#多態(tài)的三種實現(xiàn)方式(小結(jié)),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
C#使用Data?Annotations進(jìn)行手動數(shù)據(jù)驗證
這篇文章介紹了C#使用Data?Annotations進(jìn)行手動數(shù)據(jù)驗證的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-06-06
C#中使用ADOMD.NET查詢多維數(shù)據(jù)集的實現(xiàn)方法
這篇文章主要介紹了C#中使用ADOMD.NET查詢多維數(shù)據(jù)集的實現(xiàn)方法,詳細(xì)講述了C#中使用ADOMD.NET查詢多維數(shù)據(jù)集的原理與實現(xiàn)技巧,需要的朋友可以參考下2014-10-10
C#實現(xiàn)char字符數(shù)組與字符串相互轉(zhuǎn)換的方法
這篇文章主要介紹了C#實現(xiàn)char字符數(shù)組與字符串相互轉(zhuǎn)換的方法,結(jié)合實例形式簡單分析了C#字符數(shù)組轉(zhuǎn)字符串及字符串轉(zhuǎn)字符數(shù)組的具體實現(xiàn)技巧,需要的朋友可以參考下2017-02-02

