天天看點

ASP.NET MVC IOC依賴注入之Autofac系列(一)- MVC當中應用

本系列主要講述IOC依賴注入之Autofac在ASP.NET MVC項目中以及在WebForm項目中的具體應用。

話不多說,直入主題看我們的解決方案結構:

ASP.NET MVC IOC依賴注入之Autofac系列(一)- MVC當中應用

分别對上面的工程進行簡單的說明:

1、TianYa.DotNetShare.Model:為demo的實體層

2、TianYa.DotNetShare.Repository:為demo的倉儲層即資料通路層

3、TianYa.DotNetShare.Service:為demo的服務層即業務邏輯層

4、TianYa.DotNetShare.MvcDemo:為demo的web層項目,MVC架構

約定:本demo的web項目為ASP.NET Web 應用程式(.NET Framework 4.5) MVC架構,實體層、倉儲層、服務層均為.NET Framework 4.5 類庫。

一、實體層

ASP.NET MVC IOC依賴注入之Autofac系列(一)- MVC當中應用

1、定義一個空接口IDependency,後面有妙用,用于一次性注入

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TianYa.DotNetShare.Model
{
    /// <summary>
    /// 空接口,用于一次性注入
    /// </summary>
    public interface IDependency
    {
    }
}      

2、建立一個學生實體 Student

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TianYa.DotNetShare.Model
{
    /// <summary>
    /// 學生類
    /// </summary>
    public class Student
    {
        /// <summary>
        /// 學号
        /// </summary>
        public string StuNo { get; set; }

        /// <summary>
        /// 姓名
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 年齡
        /// </summary>
        public int Age { get; set; }

        /// <summary>
        /// 性别
        /// </summary>
        public string Sex { get; set; }
    }
}      

demo中的實體就這樣了

二、倉儲層

ASP.NET MVC IOC依賴注入之Autofac系列(一)- MVC當中應用

本demo的倉儲層需要引用我們的實體層TianYa.DotNetShare.Model

為什麼選擇用倉儲,原因很簡單,友善我們進行個性化擴充。在資料操作的底層進行其他個性化邏輯處理。

約定:

1、接口的定義放在根目錄下,接口的實作類,統一放到Impl檔案夾,表示實作類目錄。

2、每個實體,對應一個倉儲的接口和實作類,即有多少個實體,就對應建立多少個接口和實作類。

我們建立一個Student的倉儲接口 IStudentRepository.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using TianYa.DotNetShare.Model;

namespace TianYa.DotNetShare.Repository
{
    /// <summary>
    /// 學生類倉儲層接口
    /// </summary>
    public interface IStudentRepository
    {
        /// <summary>
        /// 根據學号擷取學生資訊
        /// </summary>
        /// <param name="stuNo">學号</param>
        /// <returns>學生資訊</returns>
        Student GetStuInfo(string stuNo);
    }
}      

接着在Impl中建立一個Student的倉儲實作StudentRepository.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using TianYa.DotNetShare.Model;

namespace TianYa.DotNetShare.Repository.Impl
{
    /// <summary>
    /// 學生類倉儲層
    /// </summary>
    public class StudentRepository : IStudentRepository, IDependency
    {
        /// <summary>
        /// 根據學号擷取學生資訊
        /// </summary>
        /// <param name="stuNo">學号</param>
        /// <returns>學生資訊</returns>
        public Student GetStuInfo(string stuNo)
        {
            //資料通路邏輯,此處為了示範就簡單些
            var student = new Student();
            switch (stuNo)
            {
                case "10000":
                    student = new Student() { StuNo = "10000", Name = "張三", Sex = "男", Age = 20 };
                    break;
                case "10001":
                    student = new Student() { StuNo = "10001", Name = "錢七七", Sex = "女", Age = 18 };
                    break;
                case "10002":
                    student = new Student() { StuNo = "10002", Name = "李四", Sex = "男", Age = 21 };
                    break;
                default:
                    student = new Student() { StuNo = "10003", Name = "王五", Sex = "男", Age = 25 };
                    break;
            }

            return student;
        }
    }
}      

該類同時實作了IStudentRepository接口和IDependency接口,其中實作IDependency接口的目的是為了後面的web端進行一次性注入

三、服務層

ASP.NET MVC IOC依賴注入之Autofac系列(一)- MVC當中應用

本demo的服務層需要引用我們的實體層TianYa.DotNetShare.Model和我們的倉儲層TianYa.DotNetShare.Repository

服務層與倉儲層類似,它屬于倉儲層的使用者。定義的方式也與倉儲層類似,有接口和Impl實作目錄。

但服務層不需要一個實體對應一個,服務層更多的是按照功能子產品進行劃分,比如一個登入子產品,建立一個LoginService。

為了示範,我們建立一個Student的服務層接口IStudentService.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using TianYa.DotNetShare.Model;

namespace TianYa.DotNetShare.Service
{
    /// <summary>
    /// 學生類服務層接口
    /// </summary>
    public interface IStudentService
    {
        /// <summary>
        /// 根據學号擷取學生資訊
        /// </summary>
        /// <param name="stuNo">學号</param>
        /// <returns>學生資訊</returns>
        Student GetStuInfo(string stuNo);
    }
}      

接着我們同樣在Impl中建立一個Student的服務層實作StudentService.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using TianYa.DotNetShare.Model;
using TianYa.DotNetShare.Repository;

namespace TianYa.DotNetShare.Service.Impl
{
    /// <summary>
    /// 學生類服務層
    /// </summary>
    public class StudentService : IStudentService, IDependency
    {
        /// <summary>
        /// 定義倉儲層學醬油象類對象
        /// </summary>
        protected IStudentRepository StuRepository;

        /// <summary>
        /// 空構造函數
        /// </summary>
        public StudentService() { }

        /// <summary>
        /// 構造函數
        /// </summary>
        /// <param name="stuRepository">倉儲層學醬油象類對象</param>
        public StudentService(IStudentRepository stuRepository)
        {
            this.StuRepository = stuRepository;
        }

        /// <summary>
        /// 根據學号擷取學生資訊
        /// </summary>
        /// <param name="stuNo">學号</param>
        /// <returns>學生資訊</returns>
        public Student GetStuInfo(string stuNo)
        {
            var stu = StuRepository.GetStuInfo(stuNo);
            return stu;
        }
    }
}      

該類同時實作了IStudentService接口和IDependency接口,其中實作IDependency接口的目的是為了後面的web端進行一次性注入

四、Web層

ASP.NET MVC IOC依賴注入之Autofac系列(一)- MVC當中應用

本demo的web項目需要引用以下幾個程式集:

1、TianYa.DotNetShare.Model 我們的實體層

2、TianYa.DotNetShare.Service 我們的服務層

3、TianYa.DotNetShare.Repository 我們的倉儲層,正常我們的web項目是不應該使用倉儲層的,此處我們引用是為了示範IOC依賴注入

4、Autofac 依賴注入基礎元件

5、Autofac.Mvc5 依賴注入Mvc5的輔助元件

其中Autofac和Autofac.Mvc5可以從我們的NuGet上引用:

ASP.NET MVC IOC依賴注入之Autofac系列(一)- MVC當中應用

如果從線下已安裝的程式包源中找不到我們要的程式集,可以嘗試添加我們的程式包源,具體步驟如下:

ASP.NET MVC IOC依賴注入之Autofac系列(一)- MVC當中應用
ASP.NET MVC IOC依賴注入之Autofac系列(一)- MVC當中應用
名稱:nuget.org
源:https://api.nuget.org/v3/index.json      

添加新的包源後點選确定(如果已經有此包源就忽略該步驟),接下來就從NuGet上安裝我們需要的程式集。

ASP.NET MVC IOC依賴注入之Autofac系列(一)- MVC當中應用

依次點選下載下傳以下2個元件

ASP.NET MVC IOC依賴注入之Autofac系列(一)- MVC當中應用

到了這裡我們所有的工作都已經準備好了,接下來就是重頭戲,開始做注入工作了。

打開我們的Global.asax檔案進行注入工作

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

using Autofac;
using Autofac.Integration.Mvc;
using TianYa.DotNetShare.Model;
using TianYa.DotNetShare.Repository.Impl;
using TianYa.DotNetShare.Repository;

namespace TianYa.DotNetShare.MvcDemo
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            AutofacRegister(); //Autofac依賴注入
        }

        /// <summary>
        /// Autofac依賴注入
        /// </summary>
        private void AutofacRegister()
        {
            var builder = new ContainerBuilder();
            //注冊MVC控制器(注冊所有到控制器,控制器注入,就是需要在控制器的構造函數中接收對象)
            builder.RegisterControllers(typeof(MvcApplication).Assembly);
            //構造函數注入,對StudentRepository與接口進行注入
            builder.RegisterType<StudentRepository>().As<IStudentRepository>();

            //設定依賴解析器
            var container = builder.Build();
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
        }
    }
}      

至此,我們就完成了依賴注入工作,此方式為構造函數注入,接下來我們來看看控制器裡面怎麼弄:

using System.Web.Mvc;
using TianYa.DotNetShare.Repository;

namespace TianYa.DotNetShare.MvcDemo.Controllers
{
    public class HomeController : Controller
    {
        /// <summary>
        /// 定義倉儲層學醬油象類對象
        /// </summary>
        protected IStudentRepository StuRepository;

        /// <summary>
        /// 通過構造函數進行注入
        /// 注意:參數是抽象類,而非實作類,因為已經在Global.asax中将實作類映射給了抽象類
        /// </summary>
        /// <param name="stuRepository">倉儲層學醬油象類對象</param>
        public HomeController(IStudentRepository stuRepository)
        {
            this.StuRepository = stuRepository;
        }

        public ActionResult Index()
        {
            var stu = StuRepository.GetStuInfo("10000");
            string msg = $"學号:10000,姓名:{stu.Name},性别:{stu.Sex},年齡:{stu.Age}。";
            return Content(msg);
        }
    }
}      

至此,完成處理,接下來就是見證奇迹的時刻了,我們通路 /home/index,看看是否能傳回學生資訊。

ASP.NET MVC IOC依賴注入之Autofac系列(一)- MVC當中應用

我們可以發現,傳回了學生的資訊,說明我們注入成功了。

總結:

1、采用的是構造函數注入的方式,在構造函數中初始化指派。

2、StuRepository對象不需要執行個體化,即不需要new,降低了系統資源的消耗。

3、需要在Global.asax中對StudentRepository寫映射,如果倉儲類比較多的時候,就需要寫很多了,如何避免,這個在後面的篇幅中會講解到。

擴充: 上面講解了構造函數注入的方式,下面擴充屬性注入的方式,在Global.asax中稍微修改下注入語句即可。

将:

builder.RegisterControllers(typeof(MvcApplication).Assembly);      

改為:

builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();      

PropertiesAutowired:表示允許屬性注入。

接下來我們來看下怎麼使用,修改下我們的依賴注入語句,新增服務層學生類注入:

/// <summary>
/// Autofac依賴注入
/// </summary>
private void AutofacRegister()
{
    var builder = new ContainerBuilder();
    //注冊MVC控制器(注冊所有到控制器,控制器注入,就是需要在控制器的構造函數中接收對象)
    builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();
    //構造函數注入,對StudentRepository與接口進行注入
    builder.RegisterType<StudentRepository>().As<IStudentRepository>();
    builder.RegisterType<StudentService>().As<IStudentService>();

    //設定依賴解析器
    var container = builder.Build();
    DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}      

修改我們的控制器代碼:

using System.Web.Mvc;
using TianYa.DotNetShare.Service;

namespace TianYa.DotNetShare.MvcDemo.Controllers
{
    public class HomeController : Controller
    {
        /// <summary>
        /// 通過屬性注入,通路修飾符必須為public,否則會注入失敗
        /// </summary>
        public IStudentService StuService { get; set; }

        public ActionResult Index()
        {
            var stu = StuService.GetStuInfo("10001");
            string msg = $"學号:10001,姓名:{stu.Name},性别:{stu.Sex},年齡:{stu.Age}。";
            return Content(msg);
        }
    }
}      

再通路一下我們的/home/index

ASP.NET MVC IOC依賴注入之Autofac系列(一)- MVC當中應用

我們可以發現,傳回了學習資訊,說明我們注入成功了。

另外通過這個例子我們可以發現在注入倉儲層對象StudentRepository時,不僅控制器中注入成功了,而且在服務層中也注入成功了,說明我們的Autofac的注入是全局的。

1、通過屬性注入,通路修飾符必須為public,否則會注入失敗。

2、Autofac的注入是全局的。

擴充:以上例子我們都是将實作類映射給對應的實作類接口,那能不能直接注入實作類呢,答案是可以的。

修改下我們的依賴注入,新增我們的實作類注入語句:

/// <summary>
/// Autofac依賴注入
/// </summary>
private void AutofacRegister()
{
    var builder = new ContainerBuilder();
    //注冊MVC控制器(注冊所有到控制器,控制器注入,就是需要在控制器的構造函數中接收對象)
    builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();
    //構造函數注入,對StudentRepository與接口進行注入
    builder.RegisterType<StudentRepository>().As<IStudentRepository>(); //實作類映射給接口
    builder.RegisterType<StudentService>().As<IStudentService>();
    builder.RegisterType<StudentRepository>(); //實作類注入

    //設定依賴解析器
    var container = builder.Build();
    DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}      

再來看下我們的控制器

using System.Web.Mvc;
using TianYa.DotNetShare.Repository.Impl;

namespace TianYa.DotNetShare.MvcDemo.Controllers
{
    public class HomeController : Controller
    {
        /// <summary>
        /// 定義倉儲層學生實作類對象
        /// </summary>
        public StudentRepository StuRepositoryImpl { get; set; }

        public ActionResult Index()
        {
            var stu = StuRepositoryImpl.GetStuInfo("10002");
            string msg = $"學号:10002,姓名:{stu.Name},性别:{stu.Sex},年齡:{stu.Age}";
            return Content(msg);
        }
    }
}      
ASP.NET MVC IOC依賴注入之Autofac系列(一)- MVC當中應用

可以看出已經實作了我們具體的實作類注入

到了這裡,大家可能會發現在我們的Global.asax檔案中,所有倉儲層、服務層的類都需要一個個注冊,那如果很多類的話,那可就寫老長了,那有什麼解決方法嗎,答案是肯定的。Autofac還提供了其他方式注入,下面就介紹下我們的解決辦法。

還記得我們上面介紹倉儲層和服務層實作類的時候都實作了我們的IDependency接口嗎,接下來就派上大用場了,我們可以一次性注冊所有實作了IDependency接口的類。

修改一下我們的依賴注入方式來實作一次性注入:

using System;
using System.Linq;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using System.Reflection;
using System.IO;

using Autofac;
using Autofac.Integration.Mvc;
using TianYa.DotNetShare.Model;

namespace TianYa.DotNetShare.MvcDemo
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            AutofacRegister(); //Autofac依賴注入
        }

        /// <summary>
        /// Autofac依賴注入
        /// </summary>
        private void AutofacRegister()
        {
            var builder = new ContainerBuilder();
            //注冊MVC控制器(注冊所有到控制器,控制器注入,就是需要在控制器的構造函數中接收對象)
            //PropertiesAutowired:允許屬性注入
            builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();

            //一次性注冊所有實作了IDependency接口的類
            Type baseType = typeof(IDependency);
            Assembly[] assemblies =
                Directory.GetFiles(AppDomain.CurrentDomain.RelativeSearchPath, "*.dll").Select(Assembly.LoadFrom).ToArray();
            builder.RegisterAssemblyTypes(assemblies)
                   .Where(type => baseType.IsAssignableFrom(type) && !type.IsAbstract)
                   .AsSelf().AsImplementedInterfaces()
                   .PropertiesAutowired().InstancePerLifetimeScope();

            //設定依賴解析器
            var container = builder.Build();
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
        }
    }
}      

最後再來看下我們的控制器

using System.Web.Mvc;
using TianYa.DotNetShare.Service;
using TianYa.DotNetShare.Repository;
using TianYa.DotNetShare.Repository.Impl;

namespace TianYa.DotNetShare.MvcDemo.Controllers
{
    public class HomeController : Controller
    {
        /// <summary>
        /// 定義倉儲層學生實作類對象
        /// </summary>
        public StudentRepository StuRepositoryImpl { get; set; }

        /// <summary>
        /// 定義倉儲層學醬油象類對象
        /// </summary>
        protected IStudentRepository StuRepository;

        /// <summary>
        /// 通過屬性注入,通路修飾符必須為public,否則會注入失敗
        /// </summary>
        public IStudentService StuService { get; set; }

        /// <summary>
        /// 通過構造函數進行注入
        /// 注意:參數是抽象類,而非實作類,因為已經在Global.asax中将實作類映射給了抽象類
        /// </summary>
        /// <param name="stuRepository">倉儲層學醬油象類對象</param>
        public HomeController(IStudentRepository stuRepository)
        {
            this.StuRepository = stuRepository;
        }

        public ActionResult Index()
        {
            var stu1 = StuRepository.GetStuInfo("10000");
            var stu2 = StuService.GetStuInfo("10001");
            var stu3 = StuRepositoryImpl.GetStuInfo("10002");
            string msg = $"學号:10000,姓名:{stu1.Name},性别:{stu1.Sex},年齡:{stu1.Age}<br />";
            msg += $"學号:10001,姓名:{stu2.Name},性别:{stu2.Sex},年齡:{stu2.Age}<br />";
            msg += $"學号:10002,姓名:{stu3.Name},性别:{stu3.Sex},年齡:{stu3.Age}";
            return Content(msg);
        }
    }
}      

再次通路一下我們的/home/index

ASP.NET MVC IOC依賴注入之Autofac系列(一)- MVC當中應用

可以看出成功傳回了學生資訊,說明我們的一次性注入成功了。

至此我們就介紹完了Autofac依賴注入在MVC中的具體使用,下一章我們将繼續簡單的介紹下Autofac在普通的WebForm當中的使用。

demo源碼:

連結:https://pan.baidu.com/s/1jUbf1pk2-bSybf9OfUh8Tw 
提取碼:24ki      

參考博文:https://www.cnblogs.com/fei686868/p/10979790.html

版權聲明:如有雷同純屬巧合,如有侵權請及時聯系本人修改,謝謝!!!

繼續閱讀