ASP.NET MVC實(shí)現(xiàn)依賴(lài)注入的完整過(guò)程
前言
在java的spring中有自動(dòng)注入功能,使得代碼變得更加簡(jiǎn)潔靈活,所以想把這個(gè)功能移植到c#中,接下來(lái)逐步分析實(shí)現(xiàn)過(guò)程
1.使用自動(dòng)注入場(chǎng)景分析
在asp.net mvc中,無(wú)論是什么代碼邏輯分層,最終的表現(xiàn)層為Controller層,所以我們注入點(diǎn)就是在Controller中,這里我們需要替換默認(rèn)的ControllerFactory,掃描代碼中標(biāo)記需要注入的對(duì)象,進(jìn)行實(shí)例化注入
public class FastControllerFactory : DefaultControllerFactory
{
public override IController CreateController(RequestContext requestContext, string controllerName)
{
Type type = this.GetControllerType(requestContext, controllerName);
Object obj = GetControllerInstance(requestContext, type);
//Controller中標(biāo)記AutoWired屬性的自動(dòng)注入
List<FieldInfo> AutoWiredFieldList = type.GetRuntimeFields().Where(f => f.GetCustomAttribute(typeof(AutoWired)) != null).ToList();
foreach (FieldInfo field in AutoWiredFieldList)
{
field.SetValue(obj, InjectUtil.Container.Resolve(field.FieldType));
}
return obj as IController;
}
}
FastControllerFactory就是我們自定義的一個(gè)Controller工廠,重寫(xiě)CreateController方法,對(duì)標(biāo)記了AutoWired這個(gè)自定義注解的變量,從Bean容器中取出實(shí)例進(jìn)行賦值,同時(shí)我們還需要在Global文件中的Start方法中,進(jìn)行默認(rèn)工廠進(jìn)行替換
ControllerBuilder.Current.SetControllerFactory(new FastControllerFactory());
2.IOC容器的實(shí)現(xiàn)
c#中的自定義容器有很多開(kāi)源成熟的框架,例如AutoFac等,這里我們是自己實(shí)現(xiàn)一個(gè)輕量級(jí)的版本
源碼地址:https://gitee.com/grassprogramming/FastIOC
這里就重點(diǎn)說(shuō)一下如何在asp.net mvc中的使用,首先我們需要對(duì)需要注入的Bean對(duì)象進(jìn)行標(biāo)記,這個(gè)標(biāo)記就叫做Component,
在asp.net mvc Global文件中的Start方法中,我們需要將整個(gè)項(xiàng)目中需要自動(dòng)注入的Bean加入到容器中
public class InjectUtil
{
public static ContainerBuilder Container;
public static void Init()
{
Container = new ContainerBuilder();
//獲取所有程序集
var assemblies = System.Web.Compilation.BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToArray();
//注入所有Component組件
Container.RegisterAssemblyTypes(assemblies, typeof(Component),true);
Container.Build();
}
}
到這里Controller層面的事項(xiàng)就已經(jīng)完成了,接下來(lái)就需要在IOC容器中初始化Bean實(shí)例方法中進(jìn)一步處理
private Object GetInstance(RegisterEntity Entity)
{
Object obj = null;
if (Entity.IsEnableIntercept)
{
bool IsExtend = Entity.RealType == Entity.RegistType;
obj = DynamictProxy.CreateProxyObject(Entity.RealType, Entity.RegistType, Entity.InterceptType, IsExtend, Entity.IsInterceptAllMethod);
}
else
{
var constructors = Entity.RegistType.GetConstructors();
obj = constructors[0].Invoke(new Object[] { });
}
//這里使用單例模式將實(shí)例化Instance存儲(chǔ),提前暴露未進(jìn)行后續(xù)設(shè)置的對(duì)象實(shí)例
if (!SingleInstanceDic.ContainsKey(Entity.RealType))
{
SingleInstanceDic.Add(Entity.RealType, obj);
}
//如果這個(gè)class標(biāo)記了Component,且有標(biāo)記了AutoWired的Field,進(jìn)行自動(dòng)注入
if (Entity.RealType.GetCustomAttribute(typeof(Component), true) != null)
{
//這里要使用GetRuntimeFields,此方法返回在指定類(lèi)型上定義的所有字段,包括繼承,非公共,實(shí)例和靜態(tài)字段。
foreach (FieldInfo Field in Entity.RealType.GetRuntimeFields())
{
if (Field.GetCustomAttribute(typeof(AutoWired), true) != null)
{
Type FieldType = Field.FieldType;
if (Contains(FieldType))
{
//判斷單例存儲(chǔ)中是否包含,如果有,取出賦值,這里可以防止循環(huán)依賴(lài)導(dǎo)致的死循環(huán)
if (SingleInstanceDic.ContainsKey(FieldType))
{
Field.SetValue(obj, SingleInstanceDic[FieldType]);
}
else
{
Field.SetValue(obj, Resolve(FieldType));
}
}
}
}
}
return obj;
}
GetInstance方法就是實(shí)例化Bean對(duì)象的核心方法,其實(shí)很簡(jiǎn)單,就是通過(guò)反射創(chuàng)建對(duì)象,其中需要注意的有兩點(diǎn)
1)對(duì)于一個(gè)Bean初始化時(shí)需要掃描Bean中的所有變量,如果內(nèi)部還有依賴(lài)注入的嵌套對(duì)象,需要使用遞歸,直到?jīng)]有需要注入的Field
2)我這里使用的是單例模式,因?yàn)樵跍y(cè)試過(guò)程中可能存在在A類(lèi)中對(duì)B進(jìn)行依賴(lài)注入,在B類(lèi)中對(duì)A進(jìn)行依賴(lài)注入,常規(guī)創(chuàng)建過(guò)程,如果使用遞歸進(jìn)行掃描,就會(huì)進(jìn)入死循環(huán),內(nèi)存溢出,所以使用對(duì)象的單例,一旦創(chuàng)建就放入字典中,如果再次掃描到該對(duì)象需要注入,則直接取出使用,就避免了循環(huán)引用
3.其他
對(duì)其他不在Controller中使用的類(lèi)需要依賴(lài)注入,則需要直接從IOC的Bean容器取出使用
private AuthUtil @AuthUtil = InjectUtil.Container.Resolve<AuthUtil>();
功能到這里就全部分析完畢了,最后打個(gè)廣告,自己寫(xiě)的ASP.NET MVC快速開(kāi)發(fā)框架,希望支持一波
地址:https://gitee.com/grassprogramming/FastExecutor
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。
- .NET Core中依賴(lài)注入AutoMapper的方法示例
- 在.NET Core控制臺(tái)程序中如何使用依賴(lài)注入詳解
- 詳解ASP.NET Core 在 JSON 文件中配置依賴(lài)注入
- 詳解ASP.NET Core 中的框架級(jí)依賴(lài)注入
- 解讀ASP.NET 5 & MVC6系列教程(7):依賴(lài)注入
- ASP.NET Core 過(guò)濾器中使用依賴(lài)注入知識(shí)點(diǎn)總結(jié)
- .NET IoC模式依賴(lài)反轉(zhuǎn)(DIP)、控制反轉(zhuǎn)(Ioc)、依賴(lài)注入(DI)
- 詳解asp.net core 依賴(lài)注入
- .NET學(xué)習(xí)筆記之默認(rèn)依賴(lài)注入
相關(guān)文章
Asp.net 頁(yè)面調(diào)用javascript變量的值
開(kāi)發(fā)過(guò)程中碰到了這種情況,我想將javascript中定義的變量賦值給頁(yè)面中的TextBox控件.2009-12-12
Windows Server 2012 R2 Standard搭建ASP.NET Core環(huán)境圖文教程
這篇文章主要介紹了Windows Server 2012 R2 Standard搭建ASP.NET Core環(huán)境圖文教程,需要的朋友可以參考下2016-07-07
.Net Core + Nginx實(shí)現(xiàn)項(xiàng)目負(fù)載均衡的全步驟
這篇文章主要給大家介紹了關(guān)于.Net Core + Nginx實(shí)現(xiàn)項(xiàng)目負(fù)載均衡的相關(guān)資料,文中通過(guò)示例代碼以及圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
建立自定義的數(shù)據(jù)驅(qū)動(dòng)的本地化資源provider
本文探討了自定義的本地化資源提供者.如果想用一個(gè)可替代系統(tǒng)的資源處理方案,例如把所有的資源放入數(shù)據(jù)庫(kù)中,而不是放在分散的資源文件里,你可以自定義一個(gè)resource provider.2010-06-06
ASP.NET中實(shí)現(xiàn)文件的保護(hù)性下載基礎(chǔ)篇
許多時(shí)候,我們需要在因特網(wǎng)上提供文件下載服務(wù),但是又要防止未經(jīng)授權(quán)的下載,這時(shí)該怎么辦?本文將為讀者詳細(xì)介紹一種使用ASP.NET實(shí)現(xiàn)的HTTP處理程序的解決方案。2011-02-02
asp.net中調(diào)用存儲(chǔ)過(guò)程的方法
這篇文章主要介紹了asp.net中調(diào)用存儲(chǔ)過(guò)程的方法,結(jié)合實(shí)例形式分析了存儲(chǔ)過(guò)程的建立與asp.net調(diào)用存儲(chǔ)過(guò)程的相關(guān)技巧,需要的朋友可以參考下2016-05-05

