zoukankan      html  css  js  c++  java
  • ASP.NET Core2使用Autofac实现IOC依赖注入竟然能如此的优雅简便

    初识ASP.NET Core的小伙伴一定会发现,其几乎所有的项目依赖都是通过依赖注入方式进行链式串通的。这是因为其使用了依赖注入 (DI) 的软件设计模式,代码的设计是遵循着“高内聚、低耦合”的原则,使得各个类与类之间的关系依赖于接口,这样做的目的是能更有利于项目代码的维护与扩展。

    Autofac

    在进入主题之前咱们还是先来简单的认识下鼎鼎大名的“Autofac”吧。那么何为Autofac呢,通俗的讲就是一个开源的,且基于.NET Core、ASP.NET Core、.NET 4.5.1+等框架实现的控制反转(IOC)类库。通过Autofac可以在.NET Core、ASP.NET Core、.NET 4.5.1+等项目上很容易的实现依赖注入,代码很容易就能达到“高内聚、低耦合”的原则。另外,Autofac的中文资料也很多,需要详细了解的也可在网上自行查看。

    Autofac官方网站:https://autofac.org/

    Autofac官方的中文文档网站:https://autofaccn.readthedocs.io/zh/latest/

     

    背景

    在我们大部分的项目中都会将代码抽成多层,每层之间通过相互依赖串联工作。在这里,我们将ASP.NET Core项目代码抽成三层结构,分别为输入输出层(MVC项目)、业务层(类库)、数据层(类库),每层的功能描述如下:

    1、Lezhima.Web:接受来自客户端的请求,及服务端响应的出入口。由一个基于ASP.NET Core的MVC项目组成。

    2、Lezhima.Core:根据请求做出相应的业务判断,及调度上下游数据并计算,输出相应的业务结果给调用者。由一个基于.NET Core的类库组成。

    3、Lezhima.Data:直接跟DB进行通讯交互,实现对DB的增、删、改、查等操作。由一个基于.NET Core的类库组成。

    依赖关系:

    基于上述中的三层代码结构,我们可以清晰的看出Lezhima.Web做为项目出入口,在其需要时会调用Lezhima.Core类库,并将业务交由Lezhima.Core库处理,而Lezhima.Core类库在其需要时会调用Lezhima.Data类库操作DB。那么,它们之间的依懒关系应该是这样子的:

    1、Lezhima.Web同时依赖于Lezhima.Core与Lezhima.Data类库。

    2、Lezhima.Core依赖于Lezhima.Data类库。

    实现代码

    通过上面的介绍,我们清楚了三个分层之间的功能与依赖关系,那么接下来我们就分别来看看它们具体代码及使用Autofac如何优雅的实现依赖注入吧。

    1、首先在Lezhima.Web项目中通过NuGet管理器引用:Autofac、Autofac.Extensions.DependencyInjection两个类库。

    2、我们先来看看Lezhima.Data层的代码,首先定义一个名为“IRepository”接口,代码如下:

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Data;
      4 using System.Linq;
      5 using System.Linq.Expressions;
      6 using System.Text;
      7 using System.Threading.Tasks;
      8 
      9 namespace Lezhima.Data.Interface
     10 {
     11     public interface IRepository<T> where T : class
     12     {
     13         /// <summary>
     14         /// 从指定的表中获取符合条件的一条实体数据
     15         /// </summary>
     16         /// <param name="predicate"></param>
     17         /// <returns></returns>
     18         Task<T> GetAsync(Expression<Func<T, bool>> predicate);
     19     }
     20 }

     

    3、在Lezhima.Data层再增加一个名为“Repository”类,实现“IRepository”接口,代码如下:

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 using System.Text;
      5 using System.Threading.Tasks;
      6 using System.Data;
      7 using System.Linq.Expressions;
      8 using Microsoft.EntityFrameworkCore;
      9 using System.Data.SqlClient;
     10 using Lezhima.Data.Interface;
     11 
     12 namespace Lezhima.Data
     13 {
     14     /// <summary>
     15     /// 数据层
     16     /// 实现IRepository接口
     17     /// </summary>
     18     /// <typeparam name="T"></typeparam>
     19     public class Repository<T> : IRepository<T> where T : class
     20     {
     21 
     22         /// <summary>
     23         /// 从指定的表中获取符合条件的一条实体数据
     24         /// </summary>
     25         /// <param name="predicate"></param>
     26         /// <returns></returns>
     27         public async Task<T> GetAsync(Expression<Func<T, bool>> predicate)
     28         {
     29             using (var db = new LezhimaContext())
     30             {
     31                 if (predicate == null)
     32                     return null;
     33 
     34                 return await db.Set<T>().Where(predicate).FirstOrDefaultAsync<T>();
     35             }
     36         }
     37     }
     38 }
     39 

     

    4、在Lezhima.Core层再定义一个名为“IUserCore”接口,代码如下:

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Text;
      4 using System.Threading.Tasks;
      5 
      6 namespace Lezhima.Core.Interface
      7 {
      8     public interface IUserCore
      9     {
     10         /// <summary>
     11         /// 根据账号密码判断用户是否拥有合法登录权限
     12         /// </summary>
     13         /// <param name="email"></param>
     14         /// <returns>100成功,101账号错误,102密码错误,103参数不合法</returns>
     15         Task<MobiResult> Login(string email,string pwd);
     16     }
     17 }
     18 

    5、在Lezhima.Core层再增加一个名为“UserCore”类,实现“IUserCore”接口,代码如下:

      1 using Lezhima.Core.Interface;
      2 using Lezhima.Data.Interface;
      3 using System;
      4 using System.Collections.Generic;
      5 using System.Text;
      6 using System.Threading.Tasks;
      7 
      8 namespace Lezhima.Core
      9 {
     10     public class UserCore : IUserCore
     11     {
     12         //定义一个依赖属性
     13         private readonly IRepository<EB_User> _Repository;
     14 
     15         /// <summary>
     16         /// 通过构造涵数方式注入Data层的Repository实例
     17         /// </summary>
     18         /// <param name="repository"></param>
     19         public UserCore(IRepository<EB_User> repository)
     20         {
     21             _Repository = repository;
     22         }
     23 
     24 
     25         /// <summary>
     26         /// 根据账号密码判断用户是否拥有合法登录权限
     27         /// </summary>
     28         /// <returns>100成功,101账号错误,102密码错误,103参数不合法</returns>
     29         public async Task<MobiResult> Login(string email, string pwd)
     30         {
     31             if (string.IsNullOrEmpty(email) || string.IsNullOrEmpty(pwd))
     32                 return new MobiResult(103);
     33 
     34             //到Data层去取指定用户的数据
     35             var model= await _Repository.GetAsync(p => p.Email.Equals(email)&&p.IsDelete!=99);
     36             if(model ==null)
     37                 return new MobiResult(101);
     38 
     39             if(!model.Pwd.Equals(pwd))
     40                 return new MobiResult(102);
     41 
     42             return new MobiResult(100);
     43         }
     44 
     45     }
     46 }
     47 

    6、在Lezhima.Web层增加一个名为“AccountController ”的控制器,代码如下:

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 using System.Security.Claims;
      5 using System.Threading.Tasks;
      6 using Lezhima.Core.Interface;
      7 using Microsoft.AspNetCore.Authentication;
      8 using Microsoft.AspNetCore.Authentication.Cookies;
      9 using Microsoft.AspNetCore.Authorization;
     10 using Microsoft.AspNetCore.Http;
     11 using Microsoft.AspNetCore.Mvc;
     12 
     13 namespace Lezhima.Web.Controllers
     14 {
     15     [Authorize]
     16     [AutoValidateAntiforgeryToken]
     17     public class AccountController : Controller
     18     {
     19 
     20         //定义一个依赖属性
     21         private readonly IUserCore _UserCore;
     22 
     23         /// <summary>
     24         /// 通过构造涵数方式注入Core层的UserCore实例
     25         /// </summary>
     26         /// <param name="__UserCore"></param>
     27         public AccountController(IUserCore __UserCore)
     28         {
     29             _UserCore = __UserCore;
     30         }
     31 
     32 
     33         // GET: Account
     34         public ActionResult Index()
     35         {
     36             return View();
     37         }
     38 
     39 
     40 
     41 
     42         /// <summary>
     43         /// 实现客户端的登录操作
     44         /// </summary>
     45         /// <param name="loginRequest"></param>
     46         /// <returns></returns>
     47         [HttpPost]
     48         [AllowAnonymous]
     49         public async Task<IActionResult> Login(LoginRequest loginRequest)
     50         {
     51             var result = await _UserCore.Login(loginRequest.Email, loginRequest.Pwd);
     52 
     53             if (result.Code != 100)
     54             {
     55                 ViewBag.ResultModel = result;
     56                 return View();
     57             }
     58 
     59             //向客户端写入用户的身份cookie
     60             var _user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[]
     61             {
     62                     new Claim("UserId", user_model.UserId.ToString()),
     63             }, CookieAuthenticationDefaults.AuthenticationScheme));
     64             await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, _user);
     65 
     66             if (string.IsNullOrWhiteSpace(loginRequest.ReturnUrl))
     67             {
     68                 return RedirectToAction("Index", "Home");
     69             }
     70             return Redirect(loginRequest.ReturnUrl);
     71         }
     72 
     73     }
     74 }

    7、在Lezhima.Web层增加一个名为“Evolution”的类,用于继承Autofac的Module类,实现上述三层之间的依赖关系注入,代码如下:

      1 using Autofac;
      2 using Lezhima.Core;
      3 using Lezhima.Data;
      4 using Lezhima.Data.Interface;
      5 using System;
      6 
      7 namespace Lezhima.Web.Injection
      8 {
      9     /// <summary>
     10     /// 重写依赖注入的业务
     11     /// </summary>
     12     public class Evolution : Module
     13     {
     14         protected override void Load(ContainerBuilder builder)
     15         {
     16             //注入Data层的Repository类
     17             builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>)).InstancePerDependency();
     18             //批量注入Core层的类
     19             builder.RegisterAssemblyTypes(typeof(UserCore).Assembly)
     20                     .Where(t => t.Name.EndsWith("Core"))
     21                     .AsImplementedInterfaces();
     22         }
     23     }
     24 }
     25 

    8、在Lezhima.Web层的“Startup”类的“ConfigureServices”方法内注入即可,代码如下:

      1 public IConfiguration Configuration { get; }
      2 
      3 public IServiceProvider ConfigureServices(IServiceCollection services)
      4 {
      5 	services.AddMvc();
      6 
      7 	//将Evolution注册到项目中来,实现依赖注入
      8 	var builder = new ContainerBuilder();
      9 	builder.RegisterModule(new Evolution());
     10 	builder.Populate(services);
     11 	var container = builder.Build();
     12 	return container.Resolve<IServiceProvider>();
     13 }

      

    总结

    1、每层在调用时,通过在该类内声明一个接口类型的属性(变量),再通过Autofac构造涵数注入方式实现依赖注入并获取到相应的类实例。

    2、通过继承Autofac的Module类,并在Load方法内重写自已项目的类关系来实现注入业务。

    3、Autofac注入有多种不同的生命周期类型,分别为InstancePerLifetimeScope、SingleInstance、InstancePerDependency等,各位在项目中按需选择即可。

    4、最后再通过在ASP.NET Core项目内的“Startup”类内将注入代码类注册到项目中就可正常使用了。

    声明

    本文为作者原创,转载请备注出处与保留原文地址,谢谢。如文章能给您带来帮助,请点下推荐或关注,感谢您的支持!

  • 相关阅读:
    Codeforces Round #678 (Div. 2)
    #Dijkstra#洛谷 4943 密室
    #线性基,点分治#洛谷 3292 [SCOI2016]幸运数字
    #线性基#LOJ 114 k大异或和
    #2-SAT,Tarjan,前缀优化建边#洛谷 6378 [PA2010]Riddle
    #树形dp,二次扫描换根法#洛谷 4284 [SHOI2014]概率充电器
    #dp#洛谷 5774 [JSOI2016]病毒感染
    #Tarjan,拓扑排序#洛谷 3436 [POI2006]PRO-Professor Szu
    #差分约束,Floyd#洛谷 2474 [SCOI2008]天平
    #Tarjan,SPFA,差分约束系统#BZOJ 2330 AcWing 368 银河
  • 原文地址:https://www.cnblogs.com/Miidy/p/9604759.html
Copyright © 2011-2022 走看看