ASP.NET Core框架学习
一、Web Api架构组织
一)MVC 设计模式中的Model与Controller:
- 在 MVC 模式中,控制器(Controller)是初始入口点,负责选择要使用的模型类型和要呈现的视图
1、Model层:
- 表示应用程序和任何应由其执行的业务逻辑或操作的状态。
- 业务逻辑应与保持应用程序状态的任何实现逻辑一起封装在模型中。
- Entity层: 实体类。
namespace Library.Entity
{
//Book实体类:ID、姓名、作者
public class Book
{
public int Id { set; get; }
public string Name { set; get; }
public string Author { set; get; }
}
}
- Service层:
- 相当于对Model与Contorller的进一步解耦,里面封装了通用的业务逻辑、通用的数据接口等。
- 封装了与数据库的基本操作,供Controller层调用完成高层业务逻辑。
using Library.Entity;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Library.Services
{
//图书通用操作的的接口
public interface IBookRepository
{
Task<IEnumerable<Book>> GetBooksAsync(); //获取所有图书
Task<Book> GetBookAsync(int id); //根据ID获取相应图书
void AddBook(Book book); //增加图书
void UpdateBook(Book book); //更新图书
void DeleteBook(Book book); //删除图书
bool BookExistAsync(int id); //根据ID检测是否存在图书
}
}
using Library.Entity;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Library.Services
{
//图书通用操作的实现
public class BookRepository : IBookRepository
{
//DbContext 数据库实体,由EF框架去进行SQL操作
private readonly LibraryDbContext _context;
public BookRepository(LibraryDbContext context)
{
_context = context;
}
//增加图书
public void AddBook(Book book)
{
_context.Books.Add(book);
_context.SaveChanges();
}
/// <summary>
/// 根据ID检测是否存在图书
/// </summary>
/// <param name="id"></param>
/// <returns>true or false</returns>
public bool BookExistAsync(int id)
{
return _context.Books.Any(x => x.Id == id);
}
//删除图书
public void DeleteBook(Book book)
{
_context.Books.Remove(book);
_context.SaveChanges();
}
//获取所有图书
public async Task<IEnumerable<Book>> GetBooksAsync()
{
return await _context.Books.ToListAsync();
}
//根据ID获取图书
public async Task<Book> GetBookAsync(int id)
{
return await _context.Books
.Where(x => x.Id == id)
.FirstOrDefaultAsync();
}
//更新图书
public void UpdateBook(Book book)
{
_context.Update(book);
_context.SaveChanges();
}
}
}
2、Controller层:
- 控制器作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开。
- 相当于Model与View间的中间件,处理用户交互、使用模型并最终选择要呈现的视图的组件。
- Controller层不再直接与数据库连接,而是操作Service,进而Service操作Database使其解耦,便于后期维护大量的业务逻辑。
using Library.Entity;
using Library.Services;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Threading.Tasks;
namespace Library.Controller
{
[Route("api/[controller]")]
[ApiController]
public class BooksController : ControllerBase
{
//IBookRepository 对象实体,内含通用的业务逻辑
private readonly IBookRepository _bookRepository;
public BooksController(IBookRepository bookRepository)
{
_bookRepository = bookRepository;
}
[HttpGet] //api/Books
public async Task<IActionResult> GetBooks()
{
var books = await _bookRepository.GetBooksAsync();
return Ok(books);
}
[HttpGet("{id}")]//api/Books/id
public async Task<IActionResult> GetBook(int id)
{
var book = await _bookRepository.GetBookAsync(id);
if (book == null)
{
return NotFound();
}
else return Ok(book);
}
[HttpDelete]
public void DeleteBook(Book book)
{
if (_bookRepository.BookExistAsync(book.Id))
{
_bookRepository.DeleteBook(book);
}
else throw new InvalidOperationException();
}
[HttpPost]
public void AddBook(Book book)
{
if (!_bookRepository.BookExistAsync(book.Id))
{
_bookRepository.AddBook(book);
}
else throw new InvalidOperationException();
}
[HttpPut]
public void UpdateBook(Book book)
{
if (_bookRepository.BookExistAsync(book.Id))
{
_bookRepository.UpdateBook(book);
}
else throw new InvalidOperationException();
}
}
}
二)Entity Framework:
- 微软提供的一个名为“Entity Framework”的ORM框架来自动化管理数据库。
- EF是一个对象关系映射(ORM)框架,使开发人员不再需要编写大量的数据库访问代码,不再手动编写CRUD。
- 使用EF,开发人员用Linq帮助他们进行查询,检索出的数据自动生成强类型对象。
DbContext:数据库上下文类:是EF中重要的一环,它是数据库与你应用程序域或实体类的桥梁。
DbContext 是负责数据与对象互操作的主要的类型。它主要负责以下一些动作:
- EntitySet : DbContext 包含所有从数据库表中被映射出来的实体对象的集合(如DbSet<>)。
- Querying : DbContext 将LINQ To Entities 转化为SQL 查询语句并发送至数据库。
- Change Tracking : 它保持变更追踪,一旦实体对象发生改变它就会从数据库中进行查询。
- Persisting Data : 它也可以基于实体状态对数据库进行插入,更新和删除操作。
- Caching : DbContext 默认作一级缓存,它存储在上下文类的生命周期中检索过的实体对象。
- Manage Relationship : 在DB-First 或 Model-First 中 DbContext 使用CSDL, MSL 和 SSDL 管理关系,在Code-First中使用流式API管理关系。
- Object Materialization : DbContext 将原始的表数据转化至实体对象中。
三)连接MySql
-
NuGet包
-
在appsettings.json中增加全局设置
"ConnectionStrings": {
"MysqlConnection": "Data Source=localhost;port=3306;Initial catalog=library;User ID=root;Password=root; treatTinyAsBoolean=false;"
}
- 在Startup类中,将 DbContext 类型添加到服务容器ConfigureServices中
services.AddDbContext<LibraryDbContext>(opthion =>
{
opthion.UseMySql(Configuration.GetConnectionString("MysqlConnection"));
});
二、基本知识
一)Startup类:
- 当host宿主机被构建时Startup类被指定调用。 通常,通过宿主机生成器上调用 WebHostBuilderExtensions.UseStartup< > 来使用。
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>(); //使用UseStarup<>
});
}
-
宿主机提供了一些能写入Startup类构造函数的服务。应用程序通过 ConfigureServices类来添加其他服务,同时主机和服务都可以在Configure 类和整个应用中使用。
-
Startup类中包括ConfigureService方法和Configure方法。
– ConfigureService:This method gets called by the runtime. Use this method to add services to the container.
- The host may configure some services before Startup methods are called.
- For features that require substantial setup, there are Add{Service} extension methods on IServiceCollection. For example, AddDbContext, AddDefaultIdentity, AddEntityFrameworkStores, and AddRazorPages
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
//依赖注入容器
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IBookRepository, BookRepository>();
services.AddDbContext<LibraryDbContext>(opthion =>
{
opthion.UseMySql(Configuration.GetConnectionString("MysqlConnection"));
});
services.AddControllers();
}
– Configure:This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
- The Configure method is used to specify how the app responds to HTTP requests.
- The request pipeline is configured by adding middleware components to an IApplicationBuilder instance.
//注入服务管道
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
- 通过依赖注入(DI)来实现控制反转(IOC)。
- ASP.NET Core 提供了一个内置的服务容器 IServiceProvider。 服务已在应用的Startup.ConfigureServices 方法中注册。
- 将服务注入到使用它的类的构造函数中。 框架负责创建依赖关系的实例,并在不再需要时对其进行处理。
- AddSingleton<TService, TImplementation>:项目启动-项目关闭 相当于静态类 只会有一个
- AddScoped<TService, TImplementation>:请求开始-请求结束 在这次请求中获取的对象都是同一个
- AddTransient<TService, TImplementation>:请求获取-(GC回收-主动释放) 每一次获取的对象都不是同一个
二)中间件/请求管道:
- 中间件是一种装配到应用管道以处理请求和响应的软件。 每个组件:
- 选择是否将请求传递到管道中的下一个组件。
- 可在管道中的下一个组件前后执行工作。
- 请求委托用于生成请求管道。 请求委托处理每个 HTTP 请求。
三)Host主机:
- 主机是封装应用资源的对象,例如:
依赖关系注入 (DI)
Logging
Configuration
IHostedService 实现
- 当主机启动时,它将对在托管服务的服务容器集合中注册的 IHostedService 的每个实现调用 IHostedService.StartAsync。 在 web 应用中,其中一个 IHostedService 实现是启动 HTTP 服务器实现的 web 服务。总而言之就是配置服务器和请求管道。
- 主机通常由 Program 类中的代码配置、生成和运行。 Main 方法:
调用 CreateHostBuilder 方法以创建和配置生成器对象。
对生成器对象调用 Build 和 Run 方法。
三、ASP.NET Core启动过程
- 其本质上是一个独立的控制台应用,它并不是必需在IIS内部托管且并不需要IIS来启动运行(而这正是ASP.NET Core跨平台的基石)。ASP.NET Core应用程序拥有一个内置的Self-Hosted(自托管)的Web Server(Web服务器),用来处理外部请求。
- 不管是托管还是自托管,都离不开Host(宿主)。在ASP.NET Core应用中通过配置并启动一个Host来完成应用程序的启动和其生命周期的管理。而Host的主要的职责就是Web Server的配置和Pilpeline(请求处理管道)的构建。
- ASP.NET Core应用的启动本质上是启动作为宿主的Host对象。
其主要涉及到两个关键对象IHostBuilder和IHost,它们的内部实现是ASP.NET Core应用的核心所在。
- CreateHostBuilder(args) :方法创建了一个IHostBuilder 抽象对象,创建过程包含CreateDefaultBuilder(args)
- CreateDefaultBuilder(args):开启创建一个默认的通用宿主机Host建造者,再通过ConfigureWebHostDefaults()方法配置开启默认的Kestrel 为默认的Web服务器并对其进行默认配置,并集成对iis的集成
- Build() :负责创建IHost,看过源代码的同学可以发现Build的过程 会配置各种东西,本身通过管道模式进行了一系列的默认或者自定义的配置以及服务注册的构建
- Run() :启动IHost。
- 从上图中我们可以看出CreateDefaultBuilder()方法主要干了五件大事:
- UseContentRoot:指定Web host使用的content root(内容根目录),比如Views。默认为当前应用程序根目录。
- ConfigureHostConfiguration :启动时宿主机需要的环境变量等相关,支持命令行
- ConfigureAppConfiguration:设置当前应用程序配置。主要是读取 appsettinggs.json 配置文件、开发环境中配置的UserSecrets、添加环境变量和命令行参数 。
- ConfigureLogging:读取配置文件中的Logging节点,配置日志系统。
- UseDefaultServiceProvider:设置默认的依赖注入容器。
- 从图中可以看出CreateDefaultBuilder 后调用了ConfigureWebHostDefaults 方法,该方法默认主要做了以下几个事情
- UseStaticWebAssets:静态文件环境的配置启用
- UseKestrel:开启Kestrel为默认的web 服务器.
- ConfigureServices:服务中间件的注册,包含路由的中间件的注册
- UseIIS:对iis 集成的支持
- UseStartup:程序Startup 启动,该启动类中可以注册中间件、扩展第三方中间件,以及相关应用程序配置的处理等等操作。
- Build()方法:
- 最终启动代码解读:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)//开启一个默认的通用主机Host建造者
.ConfigureAppConfiguration(config => {
//注册应用程序内所使用的配置文件,比如数据库链接等等
Console.WriteLine("ConfigureAppConfiguration");
})
.ConfigureServices(service =>
{
//注册服务中间件等操作
Console.WriteLine("ConfigureServices");
})
.ConfigureHostConfiguration(builder => {
//启动时需要的组件配置等,比如监听的端口 url地址等
Console.WriteLine("ConfigureHostCOnfiguration");
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}