這篇文章將為大家詳細(xì)講解有關(guān)依賴注入Autofac該如何使用,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對相關(guān)知識(shí)有一定的了解。
專注于為中小企業(yè)提供成都網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)涇川免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了上千家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。
依賴倒置?控制反轉(zhuǎn)(IOC)? 依賴注入(DI)?
你是否還在被這些名詞所困擾,是否看了大量理論文章后還是一知半解了?
今天我想結(jié)合實(shí)際項(xiàng)目,和正在迷惑中的新手朋友一起來學(xué)習(xí)和總結(jié)依賴注入Autofac的使用和理解。
public class A
{
public void A(B b)
{
// do something }
}
這樣的代碼,估計(jì)沒有程序猿不曾使用。
A類實(shí)例化的時(shí)候需要一個(gè)B的對象作為構(gòu)造函數(shù)的參數(shù),那么A就依賴B,這就叫依賴。
當(dāng)然,不用構(gòu)造函數(shù)的方式,在A類內(nèi)部去new一個(gè)B,其實(shí)也是一樣存在A依賴B。
看到“注入”一詞,第一想到的是不是注射器?哈哈,還生活在童年陰影中。 結(jié)合一下“打針”這個(gè)場景來簡單理解下依賴注入。
醫(yī)生使用注射器(Autofac),將藥物(依賴=類對象),注入到血管(其他類中)。
創(chuàng)建一個(gè)MVC項(xiàng)目,通過Nuget直接添加Autofac。
public class TestController : Controller
{
private readonly InjectionTestService _testService;
public TestController(InjectionTestService testService)
{
_testService = testService;
}
public ActionResult Index()
{
ViewBag.TestValue = _testService.Test();
return View();
}
}
public class InjectionTestService : IService { public string Test() { return "Success"; } }
在Global.asax中加入依賴注入的注冊代碼
// 創(chuàng)建一個(gè)容器var builder = new ContainerBuilder(); // 注冊所有的Controllerbuilder.RegisterControllers(Assembly.GetExecutingAssembly()); // RegisterType方式:builder.RegisterType().AsSelf().InstancePerDependency(); // Register方式:builder.Register(c => new InjectionTestService()).AsSelf().InstancePerDependency(); // 自動(dòng)注入的方式,不需要知道具體類的名稱/* BuildManager.GetReferencedAssemblies()
* 程序集的集合,包含 Web.config 文件的 assemblies 元素中指定的程序集、
* 從 App_Code 目錄中的自定義代碼生成的程序集以及其他頂級文件夾中的程序集。 */// 獲取包含繼承了IService接口類的程序集var assemblies = BuildManager.GetReferencedAssemblies().Cast()
.Where(
assembly =>
assembly.GetTypes().FirstOrDefault(type => type.GetInterfaces().Contains(typeof(IService))) != null); // RegisterAssemblyTypes 注冊程序集var enumerable = assemblies as Assembly[] ?? assemblies.ToArray();
if (enumerable.Any())
{
builder.RegisterAssemblyTypes(enumerable)
.Where(type => type.GetInterfaces().Contains(typeof(IService))).AsSelf().InstancePerDependency();
} // 把容器裝入到微軟默認(rèn)的依賴注入容器中var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
public class TestController : Controller
{
private readonly IService _testService;
public TestController(IService testService)
{
_testService = testService;
} public ActionResult Index()
{
ViewBag.TestValue = _testService.Test();
return View();
}
}
// Register 方式指定具體類builder.Register(c => new InjectionTestService()).As().InstancePerDependency(); // RegisterType 方式指定具體類builder.RegisterType().As().InstancePerDependency(); // 自動(dòng)注冊的方式 // 獲取包含繼承了IService接口類的程序集var assemblies = BuildManager.GetReferencedAssemblies().Cast()
.Where(
assembly =>
assembly.GetTypes().FirstOrDefault(type => type.GetInterfaces().Contains(typeof(IService))) != null); // RegisterAssemblyTypes 注冊程序集var enumerable = assemblies as Assembly[] ?? assemblies.ToArray();
if (enumerable.Any())
{
builder.RegisterAssemblyTypes(enumerable)
.Where(type => type.GetInterfaces().Contains(typeof(IService))).AsImplementedInterfaces().InstancePerDependency();
}
需求場景說明: 有A、B、C三個(gè)短信平臺(tái)提供發(fā)送短信業(yè)務(wù); 分別有三個(gè)短信平臺(tái)的實(shí)現(xiàn)類,AMessage,BMessage,CMessage; 客戶端在不同時(shí)段選取不同平臺(tái)發(fā)送短信。 |
常規(guī)簡單處理方式
新建三個(gè)服務(wù)類,AMsgService,BMsgService,CMsgService。
在客戶端通過 if else 的方式判斷要選用哪個(gè)短信平臺(tái),然后new服務(wù)類對象,再調(diào)用Send方法發(fā)送短信。
缺點(diǎn)
如果有新的短信平臺(tái)D加入的話,必須新建一個(gè)DSendMsgService,然后修改客戶端if else 代碼。
改造
抽象一個(gè)短信平臺(tái)的接口
public interface IMessage
{
decimal QueryBalance();
bool Send(string msg);
int TotalSend(DateTime? startDate, DateTime? endDate);
}
具體實(shí)現(xiàn)類
[MessagePlatform(Enums.MPlatform.A平臺(tái))]
public class ASendMessageService : IMessage
{ public decimal QueryBalance()
{ return 0;
} public bool Send(string msg)
{ return true;
} public int TotalSend(DateTime? startDate, DateTime? endDate)
{ return 100;
}
}
類有一個(gè)自定義屬性標(biāo)簽MessagePlatform,這個(gè)是干嘛了? 是為了給這個(gè)類做一個(gè)標(biāo)記,結(jié)合Named使用,實(shí)現(xiàn)自動(dòng)注入。
public class TestController : Controller
{
private Func _factory;
public TestController(Func factory)
{
_factory = factory;
}
public ActionResult Index()
{
var retult = _factory((int)Enums.MPlatform.A平臺(tái)).Send("去你的吧");
return View(retult);
}
}
構(gòu)造函數(shù)參數(shù)居然是一個(gè)func的委托?
這個(gè)factory傳入?yún)?shù)是一個(gè)int(定義好的短信平臺(tái)枚舉值),就可以拿到這個(gè)短信平臺(tái)具體的實(shí)現(xiàn)類?
沒錯(cuò),autofac就是這么任性。
builder.RegisterType().Named ( ( // 獲取類自定義屬性typeof(ASendMessageService).GetCustomAttributes(typeof(MessagePlatformAttribute), false).FirstOrDefault() as MessagePlatformAttribute ).platform.ToString() ).InstancePerRequest(); builder.Register >(c => { var ic = c.Resolve (); return name => ic.ResolveNamed (name.ToString()); });
疑問:
上面只是給 ASendMessageService類實(shí)現(xiàn)了自動(dòng)注入,那么BSendMessageService,CSendMessageService怎么辦了,不可能都去復(fù)制一段注入的配置代碼吧?
typeof(IMessage).Assembly.GetTypes() .Where(t => t.GetInterfaces().Contains(typeof(IMessage))) .ForEach(type => { // 注冊type });
如果你有些實(shí)現(xiàn)類不在IMessge這個(gè)程序集下,那就不能這么寫了,要結(jié)合具體項(xiàng)目情況來調(diào)整代碼。
1.依賴注入的目的是為了解耦。 2.不依賴于具體類,而依賴抽象類或者接口,這叫依賴倒置。 3.控制反轉(zhuǎn)即IoC (Inversion of Control),它把傳統(tǒng)上由程序代碼直接操控的對象的調(diào)用權(quán)交給容器,通過容器來實(shí)現(xiàn)對象組件的裝配和管理。所謂的“控制反轉(zhuǎn)”概念就是對組件對象控制權(quán)的轉(zhuǎn)移,從程序代碼本身轉(zhuǎn)移到了外部容器。 4. 微軟的DependencyResolver如何創(chuàng)建controller 【后續(xù)學(xué)習(xí)】 |
1、InstancePerDependency
對每一個(gè)依賴或每一次調(diào)用創(chuàng)建一個(gè)新的唯一的實(shí)例。這也是默認(rèn)的創(chuàng)建實(shí)例的方式。
官方文檔解釋:Configure the component so that every dependent component or call to Resolve() gets a new, unique instance (default.)
2、InstancePerLifetimeScope
在一個(gè)生命周期域中,每一個(gè)依賴或調(diào)用創(chuàng)建一個(gè)單一的共享的實(shí)例,且每一個(gè)不同的生命周期域,實(shí)例是唯一的,不共享的。
官方文檔解釋:Configure the component so that every dependent component or call to Resolve() within a single ILifetimeScope gets the same, shared instance. Dependent components in different lifetime scopes will get different instances.
3、InstancePerMatchingLifetimeScope
在一個(gè)做標(biāo)識(shí)的生命周期域中,每一個(gè)依賴或調(diào)用創(chuàng)建一個(gè)單一的共享的實(shí)例。打了標(biāo)識(shí)了的生命周期域中的子標(biāo)識(shí)域中可以共享父級域中的實(shí)例。若在整個(gè)繼承層次中沒有找到打標(biāo)識(shí)的生命周期域,則會(huì)拋出異常:DependencyResolutionException。
官方文檔解釋:Configure the component so that every dependent component or call to Resolve() within a ILifetimeScope tagged with any of the provided tags value gets the same, shared instance. Dependent components in lifetime scopes that are children of the tagged scope will share the parent's instance. If no appropriately tagged scope can be found in the hierarchy an DependencyResolutionException is thrown.
4、InstancePerOwned
在一個(gè)生命周期域中所擁有的實(shí)例創(chuàng)建的生命周期中,每一個(gè)依賴組件或調(diào)用Resolve()方法創(chuàng)建一個(gè)單一的共享的實(shí)例,并且子生命周期域共享父生命周期域中的實(shí)例。若在繼承層級中沒有發(fā)現(xiàn)合適的擁有子實(shí)例的生命周期域,則拋出異常:DependencyResolutionException。
官方文檔解釋:Configure the component so that every dependent component or call to Resolve() within a ILifetimeScope created by an owned instance gets the same, shared instance. Dependent components in lifetime scopes that are children of the owned instance scope will share the parent's instance. If no appropriate owned instance scope can be found in the hierarchy an DependencyResolutionException is thrown.
5、SingleInstance
每一次依賴組件或調(diào)用Resolve()方法都會(huì)得到一個(gè)相同的共享的實(shí)例。其實(shí)就是單例模式。
官方文檔解釋:Configure the component so that every dependent component or call to Resolve() gets the same, shared instance.
6、InstancePerHttpRequest (新版autofac建議使用InstancePerRequest)
在一次Http請求上下文中,共享一個(gè)組件實(shí)例。僅適用于asp.net mvc開發(fā)。
官方文檔解釋:Share one instance of the component within the context of a single HTTP request.
關(guān)于依賴注入Autofac該如何使用就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。