初识 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/
背景
在我们大部分的项目中都会将代码抽成多层, 每层之间通过相互依赖串联工作. 在这里, 我们将 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" 接口, 代码如下:
- using System;
- using System.Collections.Generic;
- using System.Data;
- using System.Linq;
- using System.Linq.Expressions;
- using System.Text;
- using System.Threading.Tasks;
- namespace Lezhima.Data.Interface
- {
- public interface IRepository<T> where T : class
- {
- /// <summary>
- /// 从指定的表中获取符合条件的一条实体数据
- /// </summary>
- /// <param name="predicate"></param>
- /// <returns></returns>
- Task<T> GetAsync(Expression<Func<T, bool>> predicate);
- }
- }
3, 在 Lezhima.Data 层再增加一个名为 "Repository" 类, 实现 "IRepository" 接口, 代码如下:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Data;
- using System.Linq.Expressions;
- using Microsoft.EntityFrameworkCore;
- using System.Data.SqlClient;
- using Lezhima.Data.Interface;
- namespace Lezhima.Data
- {
- /// <summary>
- /// 数据层
- /// 实现 IRepository 接口
- /// </summary>
- /// <typeparam name="T"></typeparam>
- public class Repository<T> : IRepository<T> where T : class
- {
- /// <summary>
- /// 从指定的表中获取符合条件的一条实体数据
- /// </summary>
- /// <param name="predicate"></param>
- /// <returns></returns>
- public async Task<T> GetAsync(Expression<Func<T, bool>> predicate)
- {
- using (var db = new LezhimaContext())
- {
- if (predicate == null)
- return null;
- return await db.Set<T>().Where(predicate).FirstOrDefaultAsync<T>();
- }
- }
- }
- }
4, 在 Lezhima.Core 层再定义一个名为 "IUserCore" 接口, 代码如下:
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading.Tasks;
- namespace Lezhima.Core.Interface
- {
- public interface IUserCore
- {
- /// <summary>
- /// 根据账号密码判断用户是否拥有合法登录权限
- /// </summary>
- /// <param name="email"></param>
- /// <returns>100 成功, 101 账号错误, 102 密码错误, 103 参数不合法</returns>
- Task<MobiResult> Login(string email,string pwd);
- }
- }
5, 在 Lezhima.Core 层再增加一个名为 "UserCore" 类, 实现 "IUserCore" 接口, 代码如下:
- using Lezhima.Core.Interface;
- using Lezhima.Data.Interface;
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading.Tasks;
- namespace Lezhima.Core
- {
- public class UserCore : IUserCore
- {
- // 定义一个依赖属性
- private readonly IRepository<EBUser> Repository;
- /// <summary>
- /// 通过构造涵数方式注入 Data 层的 Repository 实例
- /// </summary>
- /// <param name="repository"></param>
- public UserCore(IRepository<EBUser> repository)
- {
- Repository = repository;
- }
- /// <summary>
- /// 根据账号密码判断用户是否拥有合法登录权限
- /// </summary>
- /// <returns>100 成功, 101 账号错误, 102 密码错误, 103 参数不合法</returns>
- public async Task<MobiResult> Login(string email, string pwd)
- {
- if (string.IsNullOrEmpty(email) || string.IsNullOrEmpty(pwd))
- return new MobiResult(103);
- // 到 Data 层去取指定用户的数据
- var model= await Repository.GetAsync(p => p.Email.Equals(email)&&p.IsDelete!=99);
- if(model ==null)
- return new MobiResult(101);
- if(!model.Pwd.Equals(pwd))
- return new MobiResult(102);
- return new MobiResult(100);
- }
- }
- }
6, 在 Lezhima.Web 层增加一个名为 "AccountController" 的控制器, 代码如下:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Security.Claims;
- using System.Threading.Tasks;
- using Lezhima.Core.Interface;
- using Microsoft.AspNetCore.Authentication;
- using Microsoft.AspNetCore.Authentication.Cookies;
- using Microsoft.AspNetCore.Authorization;
- using Microsoft.AspNetCore.Http;
- using Microsoft.AspNetCore.Mvc;
- namespace Lezhima.Web.Controllers
- {
- [Authorize]
- [AutoValidateAntiforgeryToken]
- public class AccountController : Controller
- {
- // 定义一个依赖属性
- private readonly IUserCore UserCore;
- /// <summary>
- /// 通过构造涵数方式注入 Core 层的 UserCore 实例
- /// </summary>
- /// <param name="UserCore"></param>
- public AccountController(IUserCore UserCore)
- {
- UserCore = UserCore;
- }
- // GET: Account
- public ActionResult Index()
- {
- return View();
- }
- /// <summary>
- /// 实现客户端的登录操作
- /// </summary>
- /// <param name="loginRequest"></param>
- /// <returns></returns>
- [HttpPost]
- [AllowAnonymous]
- public async Task<IActionResult> Login(LoginRequest loginRequest)
- {
- var result = await UserCore.Login(loginRequest.Email, loginRequest.Pwd);
- if (result.Code != 100)
- {
- ViewBag.ResultModel = result;
- return View();
- }
- // 向客户端写入用户的身份 cookie
- var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[]
- {
- new Claim("UserId", usermodel.UserId.ToString()),
- }, CookieAuthenticationDefaults.AuthenticationScheme));
- await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, user);
- if (string.IsNullOrWhiteSpace(loginRequest.ReturnUrl))
- {
- return RedirectToAction("Index", "Home");
- }
- return Redirect(loginRequest.ReturnUrl);
- }
- }
- }
7, 在 Lezhima.Web 层增加一个名为 "Evolution" 的类, 用于继承 Autofac 的 Module 类, 实现上述三层之间的依赖关系注入, 代码如下:
- using Autofac;
- using Lezhima.Core;
- using Lezhima.Data;
- using Lezhima.Data.Interface;
- using System;
- namespace Lezhima.Web.Injection
- {
- /// <summary>
- /// 重写依赖注入的业务
- /// </summary>
- public class Evolution : Module
- {
- protected override void Load(ContainerBuilder builder)
- {
- // 注入 Data 层的 Repository 类
- builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>)).InstancePerDependency();
- // 批量注入 Core 层的类
- builder.RegisterAssemblyTypes(typeof(EBUserCore).Assembly)
- .Where(t => t.Name.EndsWith("Core"))
- .AsImplementedInterfaces();
- }
- }
- }
8, 在 Lezhima.Web 层的 "Startup" 类的 "ConfigureServices" 方法内注入即可, 代码如下:
- public IConfiguration Configuration { get; }
- public IServiceProvider ConfigureServices(IServiceCollection services)
- {
- services.AddMvc();
- // 将 Evolution 注册到项目中来, 实现依赖注入
- var builder = new ContainerBuilder();
- builder.RegisterModule(new Evolution());
- builder.Populate(services);
- var container = builder.Build();
- return container.Resolve<IServiceProvider>();
- }
总结
1, 每层在调用时, 通过在该类内声明一个接口类型的属性(变量), 再通过 Autofac 构造涵数注入方式实现依赖注入并获取到相应的类实例.
2, 通过继承 Autofac 的 Module 类, 并在 Load 方法内重写自已项目的类关系来实现注入业务.
3,Autofac 注入有多种不同的生命周期类型, 分别为 InstancePerLifetimeScope,SingleInstance,InstancePerDependency 等, 各位在项目中按需选择即可.
4, 最后再通过在 ASP.NET Core 项目内的 "Startup" 类内将注入代码类注册到项目中就可正常使用了.
来源: https://www.cnblogs.com/Andre/p/9604759.html