张德长

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

ASP.NET Core学习笔记2

ASP.NET Core学习笔记2

 

 

 

 

 

 

table标签:table 表格

tfoot标签:table foot 表的脚注

thead标签:table head 定义表格的标题

th标签: table header cell 表头单元格

td标签: table data cell 表数据单元格

tr标签:table row 定义表格一行

<%=%>、<%%>、<%@%>、<%#%>的区别

1、<%= %>

嵌入C#表达式

里面放变量名,获取后台的变量值,直接输入变量到页面上,里面放的变量名,未经过encode

eg:    后台: seession["ab"]=ab;    前台:<%= session["ab"] %>   === 取值

<%:%> 里面放的变量名,经过encode

     <%=%> <% = expression %> 用于解析表达式

2、<% %>

嵌入C#代码

 

<%%>之间可以写服务器端代码,中间一般放函数或方法,典型的asp程序写法

<% %>嵌入式代码块是在呈现页面的过程中执行的服务器代码。

块中的代码可以执行编程语句,并调用当前页类中的函数。

eg:    <%    for(var i=0;i<10;i++)    {     }    %>

后台:public string GetString(){}

前台:<% GetString(); %>

3、<%@%>

表示引用

<%@...%>这个是页面指令,一般放在每个页面的最顶部,对页面的运行进行控制,如设置缓存,引用用户控件,导入命名空间

 eg:<%@ Page Language="C#" %>

4、<%# %>

数据绑定

服务器端控件的数据上下文绑定,只能用在数据绑定控件中

ASP.Net MVC中的@与<% %>

区别

@

<% %>

视图引擎

Razor(cshtml)

ASPX(C#)

位置

@ 后面放置C#代码

<% %>之间放置C#代码

作用

嵌入C#代码,实现html和C#混编

嵌入C#代码,实现html和C#混编

优劣

写法简洁

写法复杂

布局视图

原因

大多数的Web应用程序网站通常包含以下部分:Header头部,Footer页脚,Menu导航菜单,View具体内容视图;

为了所有页面具有相同的布局,其中一个方法是每个页面视图都添加相同的元素,这将导致每个页面都具有很多重复性元素,最为严重的是,一旦修改布局,则要修改成百上千的视图页,维护工作量相当大;

另个一方法就是使用布局视图技术 ,该布局视图拥有通用的布局元素,具体的视图页中只需编写不同的显示代码即可,也就是说,布局视图相当于一个框架,对于不同的内容,均套在这个框架里面,从而保证所有视图的布局一致性;

 

代码

<!DOCTYPE html>

<html>

<head>

    <meta name="viewport" content="width=device-width" />

    <title>@ViewBag.Title</title>

</head>

<body>

    <div>

        @RenderBody()

    </div>

</body>

</html>

 

使用布局视图

布局视图的文件名和普通视图一样,都是cshtml;

使用布局视图:

方法一:在每个视图页中添加Layout属性;

@{Layout=”~/Views/Shared/_Layout.cshtml”;ViewBag.Title=”Student Details”;}

方法二:在每个视图中使用渲染节点;

@RenderSection(“Scripts”,required:false);

@if(IsSection(“Scripts”)){@RenderSection(“Scripts”,required:false);}

 

布局视图优先级

_ViewStart.cshtml文件,支持分层,优先级如下:

1. 视图文件中的Layout属性;

2. 同文件夹中的_ViewStart.cshtml文件;

3. 父文件夹中的_ViewStart.cshtml文件;

4. 父父文件夹中的_ViewStart.cshtml文件;

这样,就可以实现,在不同的目中层次中的视图文件,使用不同的布局;

可以创建多个不同的视图文件,以适应不同的场合:

_AdminLayout.cshtml

_NonAdminLayout.cshtml

或者在同一个布局文件中,通过条件判断,以使用不同的布局;

@{

if(User.IsInRole(“Admin”)){Layout=”_AdminLayout”;}

else {Layout=”_NonAdminLayout”;}

}

 

命名空间导入

_ViewImport.cshtml文件,向所有视图文件添加相同的命名空间;

该文件通常放在Views文件夹中;当然也可以放在各级子文件夹中;

_ViewImport.cshtml文件同样支持分层功能,优先级顺序同_ViewStart.cshtml文件;

@using MockSchoolManagement.Models

@using MockSchoolManagement.ViewModels

 

支持的指令

_ViewImport.cshtml文件支持的@指令包括:

1) @using

2) @addTagHelper

3) @removeTagHelper

4) @tagHelperPrefix

5) @model

6) @inherits

7) @inject

ASP.Net Core MVC中的路由

两种路由技术

常规路由和属性路由

路由的定义

浏览器的请求到达应用程序时,MVC中的控制器会处理传入的HTTP请求,并响应用户操作;

请求的URL会被映射到控制器的操作方法上,这个映射过程就是由应用程序的路由规则来完成;

举例

http:://localhost:12345/Home/Index,其中的Home会映射到HomeController控制器类,而Index会映射到HomeController类中的Index()方法;

Home/Details/1会映射到HomeController类中的Details()方法,方法的参数是1;也就是HomeController类→Details(id=1)

 

 

 

默认路由

在Startup.cs文件中的Configure()方法中:

public Config(IApplicationBuilder app,IHostingEnvironment env)

{

if(env.IsDevelopment()){app.UseDeveloperExceptionPage();}

app.UseStaticFiles();

app.UseMvcWithDefaultRout();

}

其中的UseMvcWithDefaultRout()就将MVC和默认路由添加到了应用程序的请求处理管道中;

默认路由规则是{controller=Home}/{action=Index}/{id?}

使用默认路由的代码:

public static IapplicationBuilder UseMvcDefaultRout(this IapplicationBuilder app)

{

if(app==null){throw new ArgumentNullException(nameof(app));}

return app.UseMvc(routs=>

{

routs.MapRout(name:”default”,template:”{controller=Home}/{action=Index}/{id?}”;)

})

}

默认路由举例

http://localhost:1234/Student/Details/1

这个映射过程称为模型绑定;

id后面的?表示该参数可选;

Student

StudentController类

Details

Details(int id)方法

/1

id参数

{controller=Home}表示controller的默认值是Home;

{action=Index}表示action的默认值是Index;

{id?}表示id是一个可选参数;

http://localhost:1234程序导航到应用程序根目录,则会使用默认的controller值和默认的action值;

 

自定义路由

使用UseMvc()方法而不是使用UseMvcWithDefaultRout();

app.UseMvc(routes=>

routes.MapRoute(“default”,”{controller=Home}/{action=Index}/{id?}”);)

属性路由

public class HomeController:Controller

{

[Route(“”)]

[Route(“Home”)]

[Route(“Home/Index”)]

public ViewResult Index(){return View();}

}

[Route(“”)]

http://localhost:4560/

[Route(“Home”)]

http://localhost:4560/Home

[Route(“Home/Index”)]

http://localhost:4560/Home/Index

3种路由规则都会访问HomeController类中的Index()方法;

可选参数

public class HomeController:Controller

{

private IStudentRepository _studentRepository;

//使用构造注入IStudentRepository 

public HomeController(IStudentRepository studentRepository)

{_studentRepository=studentRepository;}

//使用?表示id参数是可选参数,如果没有?,则id是必选参数

//?使得id参数可以为空

[Route(“Home/Details/{id?}”)]

public IActionResult Details(int ? id)

{

HomeDetailsViewModel homeDetailsViewModel=new HomeDetailsViewModel

//id??1表示,如果id不是空就使用id,如果id为空,就是用1

//相当于三元表达式id==null?1:id

{Student=_studentRepository.GetStudent(id??1),PageTitle=”学生信息”;}

return View(homeDetailsViewModel);

}

名称问题

[Route(“WC”)]

[Route(“NH/Index”)]

public string Welcome(){return “hello world”;}

属性路由中的名称和控制器名称、操作方法名称之间没有强关联关系;

多层属性路由

可以在控制器和操作方法分别标识各自的路由,而无需在控制器中的每个操作方法中标识完整路径的路由信息;

[Route(“Home/Index”)]

[Route(“Home/Student”)]

在控制器上标识控制器的路由[Route(“Home”)]

而在两个操作方法上标识各自的Action路由即可,无需多次重复标识Home路由信息;

[Route(“Index”)]

[Route(“Student”)]

如果操作方法路由上以/或者~开头,则Controller路由不会与Action路由组合在一起;

/或者~都表示从根目录开始查找该操作方法;

 

动态属性路由

[Route(“[controller]”)]标注在控制器上,[controller]就会自动替换为该控制器的名称;

[Route(“[action]”)]标注在操作方法上[action]就会自动替换为操作方法的名称;

方括号支持标记替换,如果修改了控制器或者操作方法的名称,就无需再次修改对应的Route;

 

对比

常规路由

属性路由

用于HTML页面控制器

用于RESTful API控制器

灵活性一般

灵活性更强

一次定义,终生使用

每次都要单独定义

 

服务注入的三种方式

AddSingleton

AddSingleton():首次请求会创建Singleton服务,所有后续申请都会使用相同的实例;

每个程序只创建一次Singleton服务,并在整个应用程序的声明周期使用该实例;

AddTransient

AddTransient():每次请求都会创建一个实例;

每次请求都会提供一个新实例,无论是否在同一HTTP请求的范围内,还是跨越不同的HTTP请求;

AddScoped

AddScoped():在范围内的每个请求创建一个新的AddScoped实例;

不同的HTTP请求分别创建不同的实例;

同一个Web请求中的其他服务在调用这个请求的时候,都会使用该实例;

AddScoped在一个客户端请求中是相同的,在多个客户端请求中是不同的;

在限定的HTTP请求范围内获得相同的实例,但是跨不同的HTTP请求将获得新实例;

AddScoped在当前HTTP请求的整个生命周期内可用;

 

 

 

模型绑定、模型验证

定义

模型绑定,就是将HTTP请求中的数据,映射到操作方法的对应参数上;

MVC将请求的数据绑定到操作方法对应的参数中,这个过程就叫模型绑定;

查找数据

模型绑定将按照下列顺序查找HTTP请求中的数据:

Form Values 表单中的数据

Route Values路由中的值

Query Strings 查询字符串

验证属性

ASP.Net Core内置的模型验证属性

属性

作用

Required

该字段是必须的

Range

指定允许的最大值和最小值

MinLength

指定字符串最小长度

MaxLength

指定字符串最大长度

Compare

比较模型的2个属性

例如,比较Email和ConfirmEmail属性;

RegularExpression

正则表达式,验证提供的值是否匹配正则表达式

 

 

例子

[Display(Name=”名字”)]

[Required(ErrorMessage=”请输入名字,不能为空”)]

public string Name{get;set;}

[Display(Name=”电子邮箱”)]

[RegularExpression(@”^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-]+$”,

ErrorMessage(“邮箱格式不正确”))]

[Required(ErrorMessage(“请输入邮箱,不能为空”))]

public string Email{get;set;}

 

 

TageHelper

定义

TagHelper是服务器端的组件,他们在服务器上运行;

TagHelper在Razor文件中创建和渲染HTML元素;

TagHelper类似于HTML TagHelper;

TagHelper可以提高生产效率,生成更加稳定、可靠、可维护的代码;

导入

_ViewImports.cshtml文件中导入TagHelper

@addTagHelper *,Microsoft.AdpNetCore.Mvc.TagHelpers

*表示要导入MVC中的所有TagHelper;

Microsoft.AdpNetCore.Mvc.TagHelpers是内置的TagHelper组件的位置;

示例

<a href=”/home/details/@student.Id”>查看</a>

@Html.ActionLink(“查看”,”details”,new{id=student.Id})

@Url.Action(“details”,”home”,new{id=student.Id})

<a asp-controller=”home”asp-action=”details” asp-route-id=”@student.Id”>查看</a>

 

优点

TagHelper是根据应用程序的路有模板自动生成的链接;

如果更改路由模板,则TagHelper会针对新的路有模板进行自动修改和适配;

路由模板修改后,TagHelper生成的链接依然能够正常工作;

如果硬编码超链接,当修改 路由模板时,必须在很多地方修改对应的超链接,这样很傻;

Image

Image TagHelper,服务器上的图片更改了就从服务器下载图片,否则就从本地缓存加载图片;

<img src=”~images/noimage.png”asp-append-version=”true”/>

Image TagHelper增强了img的标签属性,为静态图像文件提供了缓存清除行为,通过散列计算生成唯一的散列值并将其附加到img的URL中。

唯一的散列值会提示客户端从服务器重新加载图片,而不是从浏览器的缓存重新加载;

只有当服务器上的图片更改时,才会计算并缓存新的散列值;

如果图片未更改,则不会重新计算散列值,使用此散列值,浏览器会跟踪服务器上的图片内容是否已更改;

Environment TagHelper,根据不同的环境呈现不同的内容;

TagHelper

Form TagHelper

Label TagHelper

Input TagHelper

Select TagHelper

Textarea TagHelper

Validation TagHelper

EntityFramework Core

EF Core

EntityFramework Core简称为EF Core;

EF Core是ORM框架,是轻量级的、可扩展的、开源的软件;

EF Core是跨平台的,适用于Windows、maxOS、Linux;

EF Core是微软官方推荐的数据访问平台;

EF Core可以完成对数据库的增删改查这些琐事,从而节省大量时间;

EF Core 就是应用程序代码和数据库之间的粘合剂,避免了在没有ORM情况下编写大量代码来访问数据库;

ORM

ORM=Object Relational Mapper对象关系映射;

ORM会帮助我们生成底层的SQL语句,让我们可以使用应用程序业务对象;

ORM减少了开发人员编写的代码量;

如果不适用ORM,则需要很多访问数据库的代码或者SQL语句;

ORM将数据库中的数据表映射称为类对象,这些类称为领域模型、实体类、模型类、领域类;

如无哦没有ORM,则要通过ADO.NET手动编写连接SQL数据库的类,这样做不但低效,而且很不安全,容易出现SQL注入漏洞问题;

比如增删改查等底层数据库表中的数据,必须在程序中编写代码,生成SQL语句;

当数据需要显式时,又需要编写自定义代码将数据库映射到模型;

 

单层Web应用

只有一个Web库,通过这个库,以自建文件夹的形式将各个服务拆分开来;

n Models文件夹用于存放实体;

n DataRepositories用于存放仓储内容;

n ViewModels用于存放视图模型;

n Controller用于存放控制器;

n Views用于存放控制器对应的视图;

三层架构

1. 界面层;

2. 业务逻辑层BLL;

3. 数据访问层DAL;

这些层都是单独的项目;

 

四层架构

领域驱动架构DDD包含4个基本层:

展现层Presentation:向用户提供一个接口,和用户进行交互,也就是Web单层;

应用层Application:是展现层和领域层的中间者,协调业务对象去执行特定的任务,可以对 复杂的业务逻辑进行功能拼接;

领域等Domain:包括业务对象和业务规则,这是应用程序的核心层,用于存放领域实体及重要逻辑的实现;

基础设施层Infrastructure:提供通用上几乎来支持高层;基础设施层的仓储Repository可以通过ORM实现数据库的交互,或者提供发布邮件的支持;

展现层

多页MVC、WebApi

应用层

针对用户场景、用例设计应用层服务,隔离底层细节

领域层

专注于维护业务规则

编写业务代码和其处理流程时,尽量在纯粹的内存环境总进行考虑,更有利于引入设计模式,不会被底层存储细节打断思路

基础设施层/持久化

负责数据库查询和持久化存储

上述4层通过创建类库(.NET Core类库)进行隔离;

 

NuGet

NuGet是一个开源软件包管理系统,原名NuPack;

NuGet作为VS的扩展,能够简化在VS中添加、更新、删除库的操作;

NuGet包被打包成ZIP压缩文件,文件扩展名.nupkg,使用开放打包约定OPC格式,包含编译代码DLL,与该代码相关的其他文件以及描述性清单;

NuGet最大的优势就是,可以方便的进行程序包的管理、发布、升级;

如果将SQLServer作为程序的数据库,需要安装Microsoft.EntityFrameworkCore.SqlServer,这个NuGet包称为数据库提供程序包;

通过NuGet安装的包称为程序包或者NuGet包;

如果使用MySQL数据库,则需要安装Micorsoft.EntityFrameworkCore.MySql;

如果使用PostgreSQL数据库,则需要安装Micorsoft.EntityFrameworkCore.PostgreSQL;

 

仓储模式

Repository表示存储库、仓储;

仓储模式是数据访问层的抽象呈现;

仓储模式隐藏了底层的数据源保存、查询的详细信息;

具体如何保存、查询数据的详细代码都在对应的仓储中;

仓储,用于保存、查询内存中集合的数据;

仓储,可以保存、查询数据库中的数据;(SQLServer、MySQL等)

可以建立一个基于Student类的仓储,完成基于学生信息的增删改查操作,而无需编写大量代码;

仓储接口

使用接口IStudentRepository来指定仓储模式,规则如下:

1. 仓储支持哪些操作(增删改查),也就是有哪些函数/方法;

2. 每个操作(函数/方法)所需的参数和返回值;

3. 仓储接口只包含它可以执行的操作,但是不包含具体的实现;(接口只声明函数,而不实现)

4. 具体的实现细节位于实现仓储接口的具体的实现类中;

简而言之,要明确接口有哪些成员函数、每个函数的参数和返回值是什么,接口中的函数只有声明而没有具体实现,具体实现要写在对应的实现类中;

优点

仓储模式的好处:

使代码更清晰、容易重用和维护;

有助于创建松耦合的系统;

如果要使用Oracle数据库,只需实现OracleRepository,然后再用依赖注入来注册OracleRepository即可;

单元测试项目中,容易使用模拟仓储代替实际仓储;

仓储模式不特定于数据库模式;

迁移

EF Core 迁移是指,将数据库架构和应用程序的领域模型(实体类)保持同步;

如果没有执行初始化迁移就运行项目,则会报错;

正确的做法:先创建迁移记录 ,通过执行该迁移来创建数据库

使用迁移:可以使用程序包管理器控制台PMC或者NetCore命令行界面CLI;

迁移中的命令:

get-help about_entityframeworkcore提供Entity Framework Core的帮助信息;

Add-Migration添加迁移记录;

Update-Datebase将数据库更新为指定的迁移;

组合使用get-help Add-Migration、get-help Update-Datebase;

规则:要先安装NuGet包Microsoft.EntityFrameworkCore.Tools,才能使用迁移命令

迁移后,会自动创建一个Migration文件夹,文件夹中有一个InitialCreate.cs文件,该文件包含了创建相应数据库表所需的代码内容;

还有一个文件是AppDbContextModelSnapShot.cs文件;

执行迁移代码可以创建表;如果数据库尚不存在,则会先创建数据库,然后创建数据表;

使用Update-Database命令,可以更新数据库;

 

 

播种

 

种子数据:EF Core可以为数据库中的表添加初始数据,这些数据也叫做种子数据;

播种:为数据库添加初始数据(种子数据)的过程叫做播种;

启用种子数据:在DbContext类中重写OnModelCreating()方法,并使用HasData()方法为Student实体播种数据;

public class AppDbContext:DbContext

{public AppDbContext(DbContextOptions<AppDbContext> options):base(options){}

public DbSet<Student>Students{get;set;}

protected override void OnModelCreating(ModelBuilder modelBuilder)

{modelBuilder.Entity<Student>().HasData(//这里的Student数据就是种子数据

new Student{Id=1,Name=”Tom”,Major=MajorEnum.Math,Email=”a@a.com”});

}}

将种子数据添加到数据库;

首先添加一条迁移记录Add-Migration SeedStudentsTable;

系统会自动生成迁移代码;

然后执行Update-Database命令,系统就会自动执行生成的代码,然后将数据迁移到数据库中;

protected override void OnModelCreating(ModelBuilder modelBuilder)

{modelBuilder.Entity<Student>().HasData(//这里的Student数据就是种子数据

new Student{Id=1,Name=”Tom”,Major=MajorEnum.Math,Email=”a@a.com”,

new Student{Id=2,Name=”Jerry”,Major=MajorEnum.Computer,Email=”b@a.com”,

new Student{Id=3,Name=”Jack”,Major=MajorEnum.Art,Email=”c@a.com”);}

如果更改了种子数据,那么重新添加前已记录,并重新更新数据库即可;

Add-Migration SeedStudentsTable

Update-Database

为了保持DbContext类干净,不臃肿,可以将种子数据从DbContext类移动到ModelBuilder类的扩展方法中:

public static class ModelBuilderExtensions

{//扩展方法必须放在静态类中,扩展方法也必须是静态方法

//扩展方法至少要有一个扩展类的实例参数,并且该参数前必须加this关键字;

public static void Seed(this ModelBuilder modelBuilder)

{

modelBuilder.Entity<Student>().HasData(

new Student{Id=1,Name=”Tom”,Major=MajorEnum.Math,Email=”a@a.com”,

new Student{Id=2,Name=”Jerry”,Major=MajorEnum.Computer,Email=”b@a.com”,

new Student{Id=3,Name=”Jack”,Major=MajorEnum.Art,Email=”c@a.com”

);}}

然后在DbContext 类的OnModelCreating方法中,只需一行代码就能搞定了:

protected override void OnModelCreating(ModelBuilder modelBuilder)

{modelBuilder.Seed();}

当领域类(实体类)发生变更时(例如添加字段),不需要手动对数据库架构进行更改,而应该通过迁移功能,使数据库架构和领域类(实体类)保持同步;

Add-Migration AddPhotoPathToStudents

Update-Database

要删除迁移代码文件, 可以使用Remove-Migration命令;

上传文件:

IformFile类

public interface IFormFile

{

string ContentType{get;}//获取上传文件的Content-Type标头

string ContentDisposition{get;}//获取上传文件的原始的Content-Disposition标头

IHeaderDictionary Headers{get;}//获取上传文件的HTTP消息头的字典信息

long Length{get;}//获取文件长度,以字节为单位

string Name{get;}//从Content-Disposition标头中获取字段名称

string FileName{get;}//从Content-Disposition标头中获取文件名

Stream OpendReadStream();//打开请求流以读取上传的文件

void CopyTo(Stream target);//将上传文件的内容复制粘贴到流

//异步的将上传文件复制粘贴到流

Task CopyToAsync(Stream target,CancellationToken cancellationToken=null);

}

要支持文件上传,表单元素应设置为enctype=“multipart/form-data”;

enctype属性,规定了在发送到服务器之前,应该如何对表单数据进行编码;

application/x-www-form-urlencoded表示在发送前编码所有字符(默认);

multipart/form-data不对字符进行编码;在使用包含文件上传空间的表单时,必须使用该值;

text/plain空格转换为加号+,但是不对特殊字符进行编码;

 

 

 

<a asp-controller=”home” asp-action=”edit” asp-route-id=”@student.Id”

class=”btn btn-primary m-1”>编辑</a>

asp-controller帮助程序定位到指定的控制器(控制器类);

asp-action帮助程序定位到指定的操作方法(方法/函数);

asp-route-id可以在路由中进行参数传递;参数传递给指定的操作方法;

ASP.NET Core

术语

相关实体:包含外键属性的实体,有时称为关系的子类;

主题实体:包含主键、备用密钥属性的实体,有时称为关系的父类;

外键:依赖实体中的属性,用于存储与实体相关的主键属性的值;

主体密钥:标识唯一主体实体的属性,可能是主键或备用密钥;

导航属性:在主体或从属实体上定义的属性,包含对相关实体的引用;

集合导航属性:一个导航属性,其中包含对多个实体的引用;

引用导航属性:保存对单个相关实体的引用的导航属性;

反向导航属性:讨论特定导航属性时,是指关系另一端的导航属性;

架构

 

架构是顶层设计;

框架是面向编程或配置的半成品;

组件是从技术维度上的复用;

模块是从业务维度上的职责划分;

系统是相互协同可运行的实体;

 

异步编码

在ASP.NET Core和EF Core的项目中,推荐使用异步方法;

为什么不用同步方法?

因为Web服务器的可用线程是有限的,而在高负载的情况下,所有线程可能都被占用;

当所有线程都被占用时,服务器无法处理新的请求,直到线程释放;

使用同步编码,可能出现多个线程被占用而无法执行任何操作的情况,因为他们正在等待IO完成;

简单点说,就是我们会感觉到网站访问速度很慢;

如果使用异步方法?

在等待IO线程时,如果使用异步编码,服务器会进行资源协调,将部分资源释放出来,用于处理当前请求;

Web服务器的可用线程总量是不变的,异步编码只是相当于一个“巧妇”,尽可能的协调资源而已;

异步编码在运行时,会增加少量开销,在低流量时,对性能的影响可以忽略不计,但是在高流量的情况下潜在性能提升很大;

 

异步方法要有async关键字、Task<T>返回值、await关键字;

public async Task<IActionResult> Index()

{return View(await _studentRepository.GetAllListAsync());}

async关键字告诉编译器,该方法的主体将生成回调,并自动创建Task<IActionResult>返回对象;

返回类型Task<IActionResult>表示该方法的返回结果是IActionResult类型;

await关键字,会使编译器将方法拆分成两个部分:

1、将异步启动的操作结束;2、当操作完成时,调用回调方法;

 

分页

前台分页:一次性查询数据库中所有记录,然后在每页中显示指定的记录;

后台分页:对数据库进行多次查询,每次只获得本页的数据;

实现分页需要3个属性:当前页、要显示的记录总数、每页显示的记录数;

 

 

分部视图

调用分部视图的3种方法:

@await Html.PartialAsync(“_Pagination”)

@Html.Partial(“_Pagination”)

<partial name=“_Pagination”/>

 

SQL语句

FromSql()从ASP.NET Core 3.0开始,该方法被弃用;

FromSqlRaw()使用纯字符串从SQL查询返回对象;

FromSqlInterpolated()使用插值字符串语法从SQL查询返回对象;

数据加载

EF Core数据加载的3种方式:

预加载:从数据库中查询处关联数据,使用方便;缺点是会加载所有数据,包括不需要加载的部分;

显示加载:通过使用DbContext.Entry()显式调用类,以加载数据,对于集合类型数据使用Collection()方法,对于单个实体使用Reference()方法;

延迟加载:表示在访问导航属性时才从数据库中加载关联数据;

预加载是EF Core推荐的数据加载方式;

性能对比:

预加载:首次读取实体时查询相关数据,通常是单次查询;

显示加载:首次读取实体时不会加载数据,只有当他需要查询相关数据时,才会向数据库发送查询指令,通常会产生多次查询;

延迟加载:读取实体时不会查询相关数据,当首次访问导航属性时,会自动查询导航属性(外键)所需的数据;每次访问导航属性的时候都会向数据库发送查询命令;

预加载性能相对较好,因为是一次加载;如果数据很复杂的时候,预加载对应的所有数据生成的SQL语句比较复杂,甚至可能会导致数据库无法有效处理EF Core生成的SQL语句

public class Department

{

public int DepartmentID{get;set;}

[Display(Name=”学院名称”)]

[StringLength(50,MinimumLength=3)]

public string Name{get;set;}

[DataType(DataType.Currency)]

[Column(TypeName=”money”)]

[Display(Name=”预算”)]

public decimal Budget{get;set;}

[TimeStamp]

public byte[] RowVersion{get;set;}

[Display(Name=””)]

public int?TeacherID{get;set;}

public virtual Teacher Administrator{get;set;}

 

}

对于导航属性(外键属性、领域模型对象属性),需要添加virtual关键字,否则会异常:

An error occurred while starting the application .InvalidOperation Exception:Navigation property’Course’on  entity type ‘CourseAssignment’is not virtual;UseLazyLoadingProxies requires all entity types to be public,unsealed ,have virtual navigation properties,and have a public or protected constructor;

继承方式

EF Core的3种继承方式:

l TPH(Table Per Hierarchy):所有数据都放在同一个表内,但是使用辨别标志Discrimination的方式进行区分,即通过Discrimination和DiscriminationID来进行区分;

l TPC(Table Per Concrete-Type):由具体类型的表来存放各自数据,而各自没有任何关联,继承的实体会包含基类中的所有属性;

l TPT(Table Per Type):每个对象各自独立产生表,这样各个表之间就没有直接关联,要额外实现关联性才能产生关联,子实体通过实体ID关联DiscriminationID找到父类;

TPH和TPC的性能比TPT好,因为TPT模式会导致复杂的连接查询;

截止到EF Core 3.1仅仅支持TPH继承;

角色验证

或验证

用户应至少具有以下角色之一才能访问控制器或操作

[Authorize(Roles ="Admin, Super User")]

 

与验证

用户应同时具有这两个角色,才能访问控制器或操作

[Authorize(Roles ="Super User")]

[Authorize(Roles ="Admin")]

ASP 授权机制

基于角色的授权

 

public string? Roles { get; set; }

// 角色,可以通过英文逗号将多个角色分隔开,从而形成一个列表

//有该角色,就可以访问

[Authorize(Roles = "Admin")]

//有其中任何一个角色,就可以访问

[Authorize(Roles = "Developer,Tester")]

[Authorize(Roles ="System,Admin")]//基于角色的授权

//同时有两个角色,才可以访问

[Authorize(Roles = "Developer")]

[Authorize(Roles = "Tester")]

基于声明的授权

 

options.AddPolicy("RankClaim", policy => policy.RequireClaim("Rank"));

该策略名称为RankClaim,要求用户具有声明Rank,具体Rank对应的值是多少,不关心,只要有这个声明就好了。

options.AddPolicy("RankClaimM3", policy => policy.RequireClaim("Rank", "M3"));

我们添加了两条策略:RankClaimP3和RankClaimM3,除了要求用户具有声明Rank外,还分别要求Rank的值为P3和M3。

options.AddPolicy("RankClaimP3OrM3", policy => policy.RequireClaim("Rank", "P3", "M3"));

options.AddPolicy("RankClaimP3AndM3", policy => policy.RequireClaim("Rank", "P3").RequireClaim("Rank", "M3"));

策略RankClaimP3OrM3要求用户具有声明Rank,且值为P3或M3即可;而策略RankClaimP3AndM3要求用户具有声明Rank,且值必须同时包含P3和M3。

基于策略的授权

 

public string? Policy { get; set; }

 options.AddPolicy("SystemOrAdmin", policy => policy.RequireRole("Admin", "System").Build());//双角色 或验证

                options.AddPolicy("SystemAndAdmin", policy => policy.RequireRole("Admin").RequireRole("System").Build());//双角色 与验证

 

身份认证方案

 public string? AuthenticationSchemes { get; set; }

// 身份认证方案,可以通过英文逗号将多个身份认证方案分隔开,从而形成一个列表

CRUD是指在做计算处理时的增加(Create)、读取(Read)、更新(Update)和删除(Delete)几个单词的首字母简写。

Swagger/OpenAPI

定义

Swagger是一个语言无关的规范,用于描述RESTful API;

Swagger项目已经捐赠给OpenAPI计划,现在它被称为OpenAPI;

Swagger是一个强大的开源工具,可以生成WebAPI的交付式文档,还可以对接口进行调试;

ASP.NET Core中,不需手动编码解析OpenAPI规范,已经有开源的Swashbuckle.ASPNetCore包;

Swashbuckle

Swashbuckle.ASPNetCore包含3个主要组件:

Swashbuckle.ASPNetCore.Swagger:将Swagger对象模型和中间件转换为SwaggerDocument对象,然后作为公开JSON;

Swashbuckle.ASPNetCore.SwaggerGen:是一个Swagger生成器,可以将SwaggerDocument从路由、控制器、模型中直接生成对象;通常与Swagger中间件结合,以生成自动公开的Swagger JSON;

Swashbuckle.ASPNetCore.SwaggerUI:是一个嵌入式多版本Swagger UI工具;可以解析Swagger JSON来构建丰富的、可定制的界面,以呈现Web API的功能;它还会包含一些内置的公共方法测试工具;

 

posted on   张德长  阅读(39)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示