【无私分享:ASP.NET CORE 项目实战(第二章)】添加EF上下文对象,添加接口、实现类以及无处不在的依赖注入(DI)
目录索引
简介
上一章,我们介绍了安装和新建控制器、视图,这一章我们来创建个数据模型,并且添加接口和实现类。
添加EF上下文对象
按照我们以前的习惯,我们还是新建几个文件夹
Commons:存放帮助类
Domians:数据模型
Services:接口和实现类
我们在Domains文件夹下添加一个类库 Domain
我们新建一个类 ApplicationDbContext 继承 DbContext
1 using Microsoft.EntityFrameworkCore; 2 3 namespace Domain 4 { 5 public class ApplicationDbContext : DbContext 6 { 7 public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) 8 : base(options) 9 { 10 } 11 12 protected override void OnModelCreating(ModelBuilder builder) 13 { 14 base.OnModelCreating(builder); 15 } 16 } 17 }
说明:
DbContext 需要引用 Microsoft.EntityFrameworkCore
第一种方式:选中 DbContext 通过组合键 Ctrl+. 添加 Microsoft.EntityFrameworkCore 引用
第二种方式:在Domain 类库的 project.json 中添加 Microsoft.EntityFrameworkCore 引用
然后,我们打开 \src\Startup.cs 修改 ConfigureServices(IServiceCollection services) 方法,增加对EF的支持(黄色高亮):
1 // This method gets called by the runtime. Use this method to add services to the container. 2 public void ConfigureServices(IServiceCollection services) 3 { 4 // Add framework services. 5 services.AddApplicationInsightsTelemetry(Configuration); 6 7 services.AddDbContext<ApplicationDbContext>(options =>options.UseSqlServer(Configuration.GetConnectionString("SqlServerConnection"))); 8 9 services.AddMvc(); 10 11 }
上面的 SqlServerConnection 是我们的数据库连接字符串,它的配置在 \src\appsettings.json 文件中(这个名字让我们想起了appsetting.config):
这样,实际上我们就完成了,但是我们后面会用到,我们目前不操作数据。
添加接口和实现类
我们来添加一个接口和实现类,来看一下Asp.net Core的依赖注入。
我们在Services文件夹下添加一个类库 Service
我们在 Service 类库下,新建 三个文件夹:
IDao:存放基础操作类
IService:存放接口文件
ServiceImp:存放实现类
IDao 我们先不管,我们后面 IRepositorycs和Repositorycs(DDD 领域驱动设计) 会使用到,我们主要是添加一个接口和实现类。为了更好的归类接口和实现类,我们在 IService 和 ServiceImp 文件夹下面分别建立一个文件夹 SysManage 用于存放系统管理接口。
我们在 \IService\SysManage\ 下新建一个接口 IUserManage
1 namespace Service.IService 2 { 3 public interface IUserManage 4 { 5 /// <summary> 6 /// 测试接口 7 /// </summary> 8 /// <returns></returns> 9 string Test(); 10 } 11 }
我们在 \ServiceImp\SysManage\ 下新建一个实现类 UserManage
1 namespace Service.ServiceImp 2 { 3 public class UserManage : IService.IUserManage 4 { 5 public string Test() 6 { 7 return "我实现了接口方法Test"; 8 } 9 } 10 }
修改 \src\Startu.cs 的 ConfigureServices(IServiceCollection services) 方法,实现注入(黄色高亮):
1 // This method gets called by the runtime. Use this method to add services to the container. 2 public void ConfigureServices(IServiceCollection services) 3 { 4 // Add framework services. 5 services.AddApplicationInsightsTelemetry(Configuration); 6 7 services.AddDbContext<ApplicationDbContext>(options =>options.UseSqlServer(Configuration.GetConnectionString("SqlServerConnection"))); 8 9 services.AddMvc(); 10 11 // Add application services. 12 services.AddTransient<Service.IService.IUserManage, Service.ServiceImp.UserManage>(); 13 }
说明:
调用接口
注入有三种方式:构造器注入、属性注入 和 方法注入。我们在 【无私分享:从入门到精通ASP.NET MVC】 系列中大部分使用的是 属性注入,今天我们使用的是 构造器注入:
我们在 HomeController 中 声明接口
private readonly IUserManage _UserManage;
在控制器构造函数中 添加:
public HomeController(IUserManage UserManage)
{
_UserManage = UserManage;
}
依赖注入框架会自动找到 IUserManage 实现类的实例,赋值给该构造函数
我们在 About 视图中 测试一下:
public IActionResult About()
{
ViewData["Message"] = _UserManage.Test();
return View();
}
Ctrl+F5 运行一下:
说明注入成功!(在Asp.net Core中,我们修改代码后直接保存刷新页面就可以,不再像以前那样 要重新编译生成,这点还是很赞的。)
三种注入方式:
构造器注入
构造器注入就在在构造函数中借助参数将依赖的对象注入到创建的对象之中。如下面的代码片段所示,Foo针对Bar的依赖体现在只读属性Bar上,针对该属性的初始化实现在构造函数中,具体的属性值由构造函数的传入的参数提供。当DI容器通过调用构造函数创建一个Foo对象之前,需要根据当前注册的类型匹配关系以及其他相关的注入信息创建并初始化参数对象。
1: public class Foo 2: { 3: public IBar Bar{get; private set;} 4: public Foo(IBar bar) 5: { 6: this.Bar = bar; 7: } 8: }
除此之外,构造器注入还体现在对构造函数的选择上面。如下面的代码片段所示,Foo类上面定义了两个构造函数,DI容器在创建Foo对象之前首选需要选择一个适合的构造函数。至于目标构造函数如何选择,不同的DI容器可能有不同的策略,比如可以选择参数做多或者最少的,或者可以按照如下所示的方式在目标构造函数上标注一个相关的特性(我们在第一个构造函数上标注了一个InjectionAttribute特性)。
1: public class Foo 2: { 3: public IBar Bar{get; private set;} 4: public IBaz Baz {get; private set;} 5: 6: [Injection] 7: public Foo(IBar bar) 8: { 9: this.Bar = bar; 10: } 11: 12: public Foo(IBar bar, IBaz):this(bar) 13: { 14: this.Baz = baz; 15: } 16: }
属性注入
如果依赖直接体现为类的某个属性,并且该属性不是只读的,我们可以让DI容器在对象创建之后自动对其进行赋值进而达到依赖自动注入的目的。一般来说,我们在定义这种类型的时候,需要显式将这样的属性标识为需要自动注入的依赖属性,以区别于该类型的其他普通的属性。如下面的代码片段所示,Foo类中定义了两个可读写的公共属性Bar和Baz,我们通过标注InjectionAttribute特性的方式将属性Baz设置为自动注入的依赖属性。对于由DI容器提供的Foo对象,它的Baz属性将会自动被初始化。
1: public class Foo 2: { 3: public IBar Bar{get; set;} 4: 5: [Injection] 6: public IBaz Baz {get; set;} 7: }
方法注入
体现依赖关系的字段或者属性可以通过方法的形式初始化。如下面的代码片段所示,Foo针对Bar的依赖体现在只读属性上,针对该属性的初始化实现在Initialize方法中,具体的属性值由构造函数的传入的参数提供。我们同样通过标注特性(InjectionAttribute)的方式将该方法标识为注入方法。DI容器在调用构造函数创建一个Foo对象之后,它会自动调用这个Initialize方法对只读属性Bar进行赋值。在调用该方法之前,DI容器会根据预先注册的类型映射和其他相关的注入信息初始化该方法的参数。
1: public class Foo 2: { 3: public IBar Bar{get; private set;} 4: 5: [Injection] 6: public Initialize(IBar bar) 7: { 8: this.Bar = bar; 9: } 10: }
希望跟大家一起学习Asp.net Core
刚开始接触,水平有限,很多东西都是自己的理解和翻阅网上大神的资料,如果有不对的地方和不理解的地方,希望大家指正!
虽然Asp.net Core 现在很火热,但是网上的很多资料都是前篇一律的复制,所以有很多问题我也暂时没有解决,希望大家能共同帮助一下!