您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關依賴注入Autofac該如何使用,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
依賴倒置?控制反轉(IOC)? 依賴注入(DI)?
你是否還在被這些名詞所困擾,是否看了大量理論文章后還是一知半解了?
今天我想結合實際項目,和正在迷惑中的新手朋友一起來學習和總結依賴注入Autofac的使用和理解。
public class A
{
public void A(B b)
{
// do something }
}
這樣的代碼,估計沒有程序猿不曾使用。
A類實例化的時候需要一個B的對象作為構造函數的參數,那么A就依賴B,這就叫依賴。
當然,不用構造函數的方式,在A類內部去new一個B,其實也是一樣存在A依賴B。
看到“注入”一詞,第一想到的是不是注射器?哈哈,還生活在童年陰影中。 結合一下“打針”這個場景來簡單理解下依賴注入。
醫生使用注射器(Autofac),將藥物(依賴=類對象),注入到血管(其他類中)。
創建一個MVC項目,通過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中加入依賴注入的注冊代碼
// 創建一個容器var builder = new ContainerBuilder(); // 注冊所有的Controllerbuilder.RegisterControllers(Assembly.GetExecutingAssembly()); // RegisterType方式:builder.RegisterType<InjectionTestService>().AsSelf().InstancePerDependency(); // Register方式:builder.Register(c => new InjectionTestService()).AsSelf().InstancePerDependency(); // 自動注入的方式,不需要知道具體類的名稱/* BuildManager.GetReferencedAssemblies()
* 程序集的集合,包含 Web.config 文件的 assemblies 元素中指定的程序集、
* 從 App_Code 目錄中的自定義代碼生成的程序集以及其他頂級文件夾中的程序集。 */// 獲取包含繼承了IService接口類的程序集var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>()
.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();
} // 把容器裝入到微軟默認的依賴注入容器中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<IService>().InstancePerDependency(); // RegisterType 方式指定具體類builder.RegisterType<InjectionTestService>().As<IService>().InstancePerDependency(); // 自動注冊的方式 // 獲取包含繼承了IService接口類的程序集var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>()
.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三個短信平臺提供發送短信業務; 分別有三個短信平臺的實現類,AMessage,BMessage,CMessage; 客戶端在不同時段選取不同平臺發送短信。 |
常規簡單處理方式
新建三個服務類,AMsgService,BMsgService,CMsgService。
在客戶端通過 if else 的方式判斷要選用哪個短信平臺,然后new服務類對象,再調用Send方法發送短信。
缺點
如果有新的短信平臺D加入的話,必須新建一個DSendMsgService,然后修改客戶端if else 代碼。
改造
抽象一個短信平臺的接口
public interface IMessage
{
decimal QueryBalance();
bool Send(string msg);
int TotalSend(DateTime? startDate, DateTime? endDate);
}
具體實現類
[MessagePlatform(Enums.MPlatform.A平臺)]
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;
}
}
類有一個自定義屬性標簽MessagePlatform,這個是干嘛了? 是為了給這個類做一個標記,結合Named使用,實現自動注入。
public class TestController : Controller
{
private Func<int, IMessage> _factory;
public TestController(Func<int, IMessage> factory)
{
_factory = factory;
}
public ActionResult Index()
{
var retult = _factory((int)Enums.MPlatform.A平臺).Send("去你的吧");
return View(retult);
}
}
構造函數參數居然是一個func的委托?
這個factory傳入參數是一個int(定義好的短信平臺枚舉值),就可以拿到這個短信平臺具體的實現類?
沒錯,autofac就是這么任性。
builder.RegisterType<ASendMessageService>().Named<IMessage>( ( // 獲取類自定義屬性typeof(ASendMessageService).GetCustomAttributes(typeof(MessagePlatformAttribute), false).FirstOrDefault() as MessagePlatformAttribute ).platform.ToString() ).InstancePerRequest(); builder.Register<Func<int, IMessage>>(c => { var ic = c.Resolve<IComponentContext>(); return name => ic.ResolveNamed<IMessage>(name.ToString()); });
疑問:
上面只是給 ASendMessageService類實現了自動注入,那么BSendMessageService,CSendMessageService怎么辦了,不可能都去復制一段注入的配置代碼吧?
typeof(IMessage).Assembly.GetTypes() .Where(t => t.GetInterfaces().Contains(typeof(IMessage))) .ForEach(type => { // 注冊type });
如果你有些實現類不在IMessge這個程序集下,那就不能這么寫了,要結合具體項目情況來調整代碼。
1.依賴注入的目的是為了解耦。 2.不依賴于具體類,而依賴抽象類或者接口,這叫依賴倒置。 3.控制反轉即IoC (Inversion of Control),它把傳統上由程序代碼直接操控的對象的調用權交給容器,通過容器來實現對象組件的裝配和管理。所謂的“控制反轉”概念就是對組件對象控制權的轉移,從程序代碼本身轉移到了外部容器。 4. 微軟的DependencyResolver如何創建controller 【后續學習】 |
1、InstancePerDependency
對每一個依賴或每一次調用創建一個新的唯一的實例。這也是默認的創建實例的方式。
官方文檔解釋:Configure the component so that every dependent component or call to Resolve() gets a new, unique instance (default.)
2、InstancePerLifetimeScope
在一個生命周期域中,每一個依賴或調用創建一個單一的共享的實例,且每一個不同的生命周期域,實例是唯一的,不共享的。
官方文檔解釋: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
在一個做標識的生命周期域中,每一個依賴或調用創建一個單一的共享的實例。打了標識了的生命周期域中的子標識域中可以共享父級域中的實例。若在整個繼承層次中沒有找到打標識的生命周期域,則會拋出異常: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
在一個生命周期域中所擁有的實例創建的生命周期中,每一個依賴組件或調用Resolve()方法創建一個單一的共享的實例,并且子生命周期域共享父生命周期域中的實例。若在繼承層級中沒有發現合適的擁有子實例的生命周期域,則拋出異常: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
每一次依賴組件或調用Resolve()方法都會得到一個相同的共享的實例。其實就是單例模式。
官方文檔解釋:Configure the component so that every dependent component or call to Resolve() gets the same, shared instance.
6、InstancePerHttpRequest (新版autofac建議使用InstancePerRequest)
在一次Http請求上下文中,共享一個組件實例。僅適用于asp.net mvc開發。
官方文檔解釋:Share one instance of the component within the context of a single HTTP request.
關于依賴注入Autofac該如何使用就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。