上一篇我们初步完善了项目的DAL层和BLL层,本章我们简单介绍下依赖注入,使用AutoFac替换系统自带的容器,并配置下WebApi环境
一、IOC容器的使用
1、依赖倒置【DIP】
什么是DIP?即为依赖倒置,面向对象编程设计原则的一种,即细节应当依赖于抽象,要针对抽象(接口)编程,而不是针对实现细节编程。所以在第二章我们对DAL层和BLL层分别添加了接口层。
2、控制反转【IOC】
什么是IOC?即为控制反转,依赖倒置原则的一种实现方法。举个例子来说:
①一个IPerson接口,存在一个Eat的方法,在实现类Person中,我们实现Eat方法返回结果;
②通常我们在其他类中调用Person类时,首先会添加引用,Person person=new Person()后,通过person.Eat()方法获取到结果,但这违反了依赖导致原则;
③另外一种设计原则—里氏替换原则提到,所有引用基类的地方应当可以透明的使用其子类的对象,所以这里我们可以使用IPerson person=new Person()实现同样的效果,但是这样做反而依赖了IPerson和Person两个对象;
④此外,若Person类后续需要改为大人和小孩,原先系统中如有几十处依赖了Person对象,我们要一下修改几十处,这是极不合理的,所以最佳方案是我们只依赖IPerson,如何实现?通过依赖注入。
3、依赖注入【DI】
DI即为依赖注入,控制反转的一种实现方法,它提供一种机制,将需要依赖对象的引用传递给被依赖对象,实现方法有构造函数注入,属性注入,方法注入,像在DAL和BLL中我们使用的就是构造函数注入。
4、IOC容器
随着系统的不断完善,依赖关系越来越多,手动方式处理会比较麻烦,所以我们可以借助IOC容器,它是一种DI框架,使用它可以简化我们的工作,通常它会包含依赖对象注入,对象生命周期管理,依赖关系映射等功能。
这里贴一张之前整理的文档(部分内容引用了一篇博客,来源找不到了,若给原作者带来困扰,请联系删除)
5、ASP.NET Core与IOC容器
ASP.NET Core中大量使用了DI(Dependency Injection)依赖注入,即在系统启动时进行服务注册,将服务添加至IOC容器中,其他的类则可以通过IOC容器请求这些服务的实例,并使用这些服务的功能。
ASP.NET Core内部是实现了IOC容器的,一共有三种:①Transient,服务每次请求都会生成一个实例;② Scoped,一次Web请求生成一个实例;③Singleton,只会产生一个实例直至应用程序停止;
在实际使用时我们需要指明映射关系,即接口与对应的实现类,但是我们发现目前我们的项目中有不少接口和实现类,难道要一个个注册吗?如果有几十几百个怎么办呢?这里我们使用AtuoFac来实现程序集级别的注入,使用Nuget引用AutoFac依赖注入插件,如下:
6、IOC容器使用
6.1、准备工作
右击依赖项,添加引用,将IBLL和IDAL勾选,另外我们要用到Model层里面的ViewModel,所以这里也一并勾上
这里我们是通过反射加载程序集的方式进行注册,虽然程序上没有添加依赖关系,当通过它们的接口引用其方法时还是需要引用它们,所以如下图所示,BLL和DAL全部选择输出到BlogSystem.Core项目的Debug文件夹下:
6.2、 替换系统容器
①在Program的CreateHostBuilder方法中将系统的服务支持工厂替换为AutoFac的工厂(Core3.1新方式):
②在Startup中添加ConfigureContainer方法,获取DAL和BLL的程序集并注册,如下:
二、WebApi简单配置
在Program类中有两个方法:①ConfigureService方法内部我们可以进行服务的注册;②Configure方法,可以配置注册过的服务(管道中间件),来使用服务包含的特性或功能;
由于我们添加项目时使用的是空模板,所以这里我们需要手动添加一些服务,
1、注册Controllers
在ConfigureService方法中添加,如下:
2、修改端点中间件
在configure方法中路由中间件会检查应用中已经注册的端点并使用,由于时WebAPI项目,所以这里我们将其改为映射控制器的方式,与此同时我们需要在控制器方法中使用特性路由(在控制器和方法上标注路由信息)
3、注册数据库服务(可忽略)
PS:这里其实可以不需要,因为我们在Model层的BlogSystemContext文件中OnConfiguring方法已经配置了数据库,这样操作反而调用了两次BlogSystemContext类(感谢园友@盛盛盛的提醒)
1、首先为startup类新增一个构造函数,将IConfiguration注入进去,并赋值给静态只读字段,如下:
2、在appsettiongs.json中我们添加数据库连接字符串,如下图:
3、然后在startup类中的ConfigurationService中添加SQLServer的服务注册
4、建立Controllers
在项目中建立Controllers文件夹,我们先建立一个UserController,继承自ControllerBase,为其添加属性路由 [Route("api/Users")]
,并为其添加标识[ApiController],它包含如下功能:①会自动要求使用属性路由,②推断参数的绑定源,③自动Http400响应,④错误状态代码问题的详细信息,⑤Multipart/form-data请求推断;
在构造函数中,我们注入IBLL服务接口;首先添加一个注册功能,为其标识为HTTPOST并为其命名,实现如下:
我们在PostMan中添加测试数据,试着注册一下,成功执行
5、密码加密
上一步我们成功注册了一个用户,但是密码没有加密,这里我们使用MD5加密下密码,简单来说就是只要对密码进行验证操作就加密后和数据库内的密码进行对比。
1、在BlogSystem.Common项目下新建一个Helpers文件夹,在里面添加一个Md5Helper类,添加如下方法
using System;
using System.Security.Cryptography;
using System.Text;
namespace BlogSystem.Common.Helpers
{
public static class Md5Helper
{
public static string Md5Encrypt(string password)
{
//判断非空
if (string.IsNullOrEmpty(password) || string.IsNullOrWhiteSpace(password))
{
return string.Empty;
}
var pwd = String.Empty;
using (MD5 md5 = MD5.Create())
{
byte[] buffer = Encoding.UTF8.GetBytes(password);
byte[] newBuffer = md5.ComputeHash(buffer);
foreach (var item in newBuffer)
{
pwd = string.Concat(pwd, item.ToString("X2"));
}
}
return pwd;
}
}
}
2、修改BLL中我们的注册方法,以及用户登录,修改用户密码方法中涉及到密码操作的部分;此外发现注册方法和修改密码方法没有返回值不利于后台判断,于是修改了方法逻辑,同时记得修改下IBLL的方法返回值,完成操作后记得重新生成解决方案覆盖下旧的dll,否则容器注入会提示错误。如下:
///
/// 用户注册
///
///
///
public async Task Register(RegisterViewModel model)
{
//判断账户是否存在
if (!await _userRepository.GetAll().AnyAsync(m => m.Account == model.Account))
{
var pwd = Md5Helper.Md5Encrypt(model.Password);
await _userRepository.CreateAsync(new User()
{
Account = model.Account,
Password = pwd
});
return true;
}
return false;
}
///
/// 用户登录
///
///
///
public async Task Login(LoginViewModel model)
{
var pwd = Md5Helper.Md5Encrypt(model.Password);
var user = await _userRepository.GetAll().FirstOrDefaultAsync(m => m.Account == model.Account && m.Password == pwd);
return user != null ? user.Id : new Guid();
}
///
/// 修改用户密码
///
///
///
public async Task ChangePassword(ChangePwdViewModel model)
{
var oldPwd = Md5Helper.Md5Encrypt(model.OldPassword);
var newPwd = Md5Helper.Md5Encrypt(model.NewPassword);
if (await _userRepository.GetAll().AnyAsync(m => m.Id == model.UserId && m.Password == oldPwd))
{
var user = await _userRepository.GetAll().FirstOrDefaultAsync(m => m.Id == model.UserId && m.Password == oldPwd);
user.Password = newPwd;
await _userRepository.EditAsync(user);
return true;
}
return false;
}
3、修改下Controller中的注册方法的逻辑,从后台把之前注册的账号删除,重新注册一个账号,完成操作
本章完~
本人知识点有限,若文中有错误的地方请及时指正,方便大家更好的学习和交流。
本文部分内容参考了博客园几位大佬的视频和文章,仅为学习和交流,视频地址如下:
solenovex,ASP.NET Core MVC 2.x 全面教程
solenovex,ASP.NET Core 3.x 入门视频
角落的白板报,《从零开始学ASP.NET Core与Entity Framework Core 》
老张的哲学,最全的 netcore 3.0 升级实战方案