ASP.NET MVC實現依賴注入

在java的spring中有自動注入功能,使得代碼變得更加簡潔靈活,因此想把這個功能移植到c#中,接下來逐步分析實現過程java

1.使用自動注入場景分析git

在asp.net mvc中,不管是什麼代碼邏輯分層,最終的表現層爲Controller層,因此咱們注入點就是在Controller中,這裏咱們須要替換默認的ControllerFactory,掃描代碼中標記須要注入的對象,進行實例化注入spring

 public class FastControllerFactory : DefaultControllerFactory
    {
        public override IController CreateController(RequestContext requestContext, string controllerName)
        {
            Type type = this.GetControllerType(requestContext, controllerName);
            Object obj = GetControllerInstance(requestContext, type);

            //Controller中標記AutoWired屬性的自動注入
            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就是咱們自定義的一個Controller工廠,重寫CreateController方法,對標記了AutoWired這個自定義註解的變量,從Bean容器中取出實例進行賦值,同時咱們還須要在Global文件中的Start方法中,進行默認工廠進行替換c#

ControllerBuilder.Current.SetControllerFactory(new FastControllerFactory());

2.IOC容器的實現mvc

c#中的自定義容器有不少開源成熟的框架,例如AutoFac等,這裏咱們是本身實現一個輕量級的版本app

源碼地址:https://gitee.com/grassprogramming/FastIOC框架

這裏就重點說一下如何在asp.net mvc中的使用,首先咱們須要對須要注入的Bean對象進行標記,這個標記就叫作Component,asp.net

在asp.net mvc Global文件中的Start方法中,咱們須要將整個項目中須要自動注入的Bean加入到容器中ide

    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層面的事項就已經完成了,接下來就須要在IOC容器中初始化Bean實例方法中進一步處理測試

       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[] { });
            }
            //這裏使用單例模式將實例化Instance存儲,提早暴露未進行後續設置的對象實例
            if (!SingleInstanceDic.ContainsKey(Entity.RealType))
            {
                SingleInstanceDic.Add(Entity.RealType, obj);
            }
        
            //若是這個class標記了Component,且有標記了AutoWired的Field,進行自動注入
            if (Entity.RealType.GetCustomAttribute(typeof(Component), true) != null)
            {
                //這裏要使用GetRuntimeFields,此方法返回在指定類型上定義的全部字段,包括繼承,非公共,實例和靜態字段。
                foreach (FieldInfo Field in Entity.RealType.GetRuntimeFields())
                {
                    if (Field.GetCustomAttribute(typeof(AutoWired), true) != null)
                    {
                        Type FieldType = Field.FieldType;
                        if (Contains(FieldType))
                        {
                            //判斷單例存儲中是否包含,若是有,取出賦值,這裏能夠防止循環依賴致使的死循環
                            if (SingleInstanceDic.ContainsKey(FieldType))
                            {
                                Field.SetValue(obj, SingleInstanceDic[FieldType]);
                            }
                            else
                            {
                                Field.SetValue(obj, Resolve(FieldType));
                            }
                           
                        }
                    }
                }
            }
            return obj;

        }

 

GetInstance方法就是實例化Bean對象的核心方法,其實很簡單,就是經過反射建立對象,其中須要注意的有兩點

1)對於一個Bean初始化時須要掃描Bean中的全部變量,若是內部還有依賴注入的嵌套對象,須要使用遞歸,直到沒有須要注入的Field

2)我這裏使用的是單例模式,由於在測試過程當中可能存在在A類中對B進行依賴注入,在B類中對A進行依賴注入,常規建立過程,若是使用遞歸進行掃描,就會進入死循環,內存溢出,因此使用對象的單例,一旦建立就放入字典中,若是再次掃描到該對象須要注入,則直接取出使用,就避免了循環引用

3.其餘

對其餘不在Controller中使用的類須要依賴注入,則須要直接從IOC的Bean容器取出使用

 private AuthUtil @AuthUtil = InjectUtil.Container.Resolve<AuthUtil>();

功能到這裏就所有分析完畢了,最後打個廣告,本身寫的ASP.NET MVC快速開發框架,但願支持一波

地址:https://gitee.com/grassprogramming/FastExecutor

相關文章
相關標籤/搜索