Asp.Net Core 学习

基于.Net Core 2.2版本的学习笔记。

常识

像Django那样自动检查代码更新,自动重载服务器(太方便了)

dotnet watch run

托管设置

设置项目文件的AspNetCoreHostingModel属性。

<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
</PropertyGroup>
  • InProcess:使用IIS服务器托管
  • OutOfProcess:使用自带Kestrel服务器托管

中间件入门

  • 可同时被访问和请求
  • 可以处理请求后,将请求传递给下一个中间件
  • 可以处理请求后,使管道短路
  • 可以传出响应
  • 中间件是按照添加顺序执行的

通过在Configure中添加参数ILogger<Startup> logger引入Asp.Net Core自带的日志组件。

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILogger<Startup> logger)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} app.UseStaticFiles(); app.Use(async (context, next) =>
{
context.Response.ContentType = "text/plain;charset=utf-8"; //await context.Response.WriteAsync("Hello!"); logger.LogDebug("M1: 传入请求");
await next();
logger.LogDebug("M1: 传出响应");
}); app.Use(async (context, next) =>
{
context.Response.ContentType = "text/plain;charset=utf-8"; logger.LogDebug("M2: 传入请求");
await next();
logger.LogDebug("M2: 传出响应");
}); app.Run(async (context) =>
{
//await context.Response.WriteAsync("你好!");
await context.Response.WriteAsync("M3: 处理请求,生成响应");
logger.LogDebug("M3: 处理请求,生成响应");
});
}

输出日志:(可以看到三个中间件的执行过程)

Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/2.0 GET https://localhost:44383/
StudyManagement.Startup:Debug: M1: 传入请求
StudyManagement.Startup:Debug: M2: 传入请求
StudyManagement.Startup:Debug: M3: 处理请求,生成响应
StudyManagement.Startup:Debug: M2: 传出响应
StudyManagement.Startup:Debug: M1: 传出响应
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 52.8954ms 200 text/plain;charset=utf-8
StudyManagement.Startup:Debug: M1: 传入请求
StudyManagement.Startup:Debug: M2: 传入请求
StudyManagement.Startup:Debug: M3: 处理请求,生成响应
StudyManagement.Startup:Debug: M2: 传出响应
StudyManagement.Startup:Debug: M1: 传出响应
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 34.3387ms 200 text/plain;charset=utf-8

静态文件支持

所有静态文件都在目录wwwroot

首先

// 设置默认文件
// 不设置的话,默认就是index.html/default.html这几个
var defaultFileOpinions = new DefaultFilesOptions();
defaultFileOpinions.DefaultFileNames.Clear();
defaultFileOpinions.DefaultFileNames.Add("test.html"); // 添加默认文件中间件,必须在UseStaticFiles之前注册
app.UseDefaultFiles(defaultFileOpinions); // 添加静态文件中间件
app.UseStaticFiles();

DirectoryBrowser 中间件

可以在浏览器浏览 wwwroot 下的内容。不推荐在生产环境中使用。

app.UseDirectoryBrowser();

FileServer 中间件

集成了UseDefaultFiles, UseStaticFiles, UseDirectoryBrowser三个中间件的功能。同样不推荐在生产环境中使用。

var fileServerOpinions = new FileServerOptions();
fileServerOpinions.DefaultFilesOptions.DefaultFileNames.Clear();
fileServerOpinions.DefaultFilesOptions.DefaultFileNames.Add("test.html"); app.UseFileServer(fileServerOpinions);

开发者异常页面

if (env.IsDevelopment())
{
var developerExceptionPageOptions = new DeveloperExceptionPageOptions();
// 显示代码行数
developerExceptionPageOptions.SourceCodeLineCount = 10;
app.UseDeveloperExceptionPage();
} app.Run(async (context) =>
{
throw new Exception("自己抛出的异常");
});

开发环境变量

  • Development:开发环境
  • Staging:演示(模拟、临时)环境
  • Production:正式(生产)环境

Ops:

  • 使用ASPNETCORE_ENVIRONMENT环境变量设置开发环境。
  • 在开发机上,在launchSettings.json文件中设置环境变量。
  • 在Staging和Production环境时,尽量在操作系统设置环境变量。
  • 使用IHostEnvironment服务访问运行时环境
  • 除了标准环境之外还支持自定义环境(UAT、QA等)

引入MVC框架

首先添加MVC服务。

public void ConfigureServices(IServiceCollection services)
{
// 单纯引入核心MVC服务,只有核心功能
services.AddMvcCore();
// 一般用这个,功能多
services.AddMvc();
}

添加中间件

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILogger<Startup> logger)
{
if (env.IsDevelopment())
{
var developerExceptionPageOptions = new DeveloperExceptionPageOptions();
// 显示代码行数
developerExceptionPageOptions.SourceCodeLineCount = 10;
app.UseDeveloperExceptionPage();
} app.UseStaticFiles();
app.UseMvcWithDefaultRoute();
}

MVC路由规则:/控制器名称/方法名称,(不区分大小写)

例如下面例子的路由是:/home/index

HomeController代码:

public class HomeController : Controller
{
public string Index()
{
return "home controller";
}
}

初步了解模型和依赖注入

定义模型

public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public string ClassName { get; set; }
public string Email { get; set; }
}

定义接口

public interface IStudentRepository
{
Student GetById(int id);
void Save(Student student);
}

实现接口

目前还没接入数据库,定义一个假数据的类

public class MockStudentRepository : IStudentRepository
{
private List<Student> _students; public MockStudentRepository()
{
_students = new List<Student>
{
new Student { Id=1, Name="小米", ClassName="红米", Email="hello1@deali.cn" },
new Student { Id=2, Name="华为", ClassName="荣耀", Email="hello2@deali.cn" },
new Student { Id=3, Name="oppo", ClassName="vivo", Email="hello3@deali.cn" },
};
} public Student GetById(int id)
{
return _students.FirstOrDefault(a => a.Id == id);
} public void Save(Student student) => throw new NotImplementedException();
}

注册依赖注入

Asp.Net Core依赖注入容器注册服务有三种

  • AddSingleton
  • AddTransient
  • AddScoped

依赖注入的优点

  • 低耦合
  • 高测试性,更加方便进行单元测试
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// 注册依赖注入,将实现类与接口绑定
services.AddSingleton<IStudentRepository, MockStudentRepository>();
}

在模型中使用依赖注入

public class StudentController : Controller
{
private readonly IStudentRepository _studentRepository; // 通过构造函数注入的方式注入 IStudentRepository
public StudentController(IStudentRepository studentRepository)
{
_studentRepository = studentRepository; } public JsonResult Index(int id)
{
return Json(_studentRepository.GetById(id));
}
}

控制器入门

内容格式协商

在控制器方法中使用 ObjectResult 返回类型,支持内容协商,根据请求头参数返回数据,

// 支持内容格式协商
public ObjectResult Details(int id)
{
return new ObjectResult(_studentRepository.GetById(id));
}

如:

Accept: application/xml

将返回xml格式。注:还要添加xml序列化器。

public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
// 注册XML序列化器
.AddXmlSerializerFormatters();
}

视图入门

将数据从控制器传递到视图的方法

前两种都是弱类型的

  • ViewData
  • ViewBag
  • 强类型视图

ViewData

  • 弱类型字典对象
  • 使用string类型的键值,存储和chaxun
  • 运行时动态解析
  • 没有智能感知,编译时也没有类型检查

使用方法:

ViewData["Title"] = "学生视图";
ViewData["Model"] = model;

cshtml代码:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<h1>@ViewData["Title"]</h1>
@{
var student = ViewData["model"] as StudyManagement.Models.Student;
}
<div>姓名:@student.Name</div>
<div>班级:@student.ClassName</div>
</body>
</html>

ViewBag

// 直接给动态属性赋值
ViewBag.PageTitle = "ViewBag标题";
ViewBag.Student = model;

cshtml使用:

<h1>@ViewBag.PageTitle</h1>
<div>姓名:@ViewBag.Student.Name</div>
<div>班级:@ViewBag.Student.ClassName</div>

强类型视图

在控制器中传给View()模型

public IActionResult GetView()
{
var model = _studentRepository.GetById(1);
return View(model);
}

在cshtml中指定模型类型

@model StudyManagement.Models.Student
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<h1>强类型模型</h1>
<ul>
<li>@Model.Id</li>
<li>@Model.Name</li>
<li>@Model.ClassName</li>
<li>@Model.Email</li>
</ul> </body>
</html>

ViewModel 视图模型

类似于DTO(数据传输对象)

定义ViewModel

public class StudentDetailsViewModel
{
public Student Student { get; set; }
public string PageTitle { get; set; }
}

修改控制器

public IActionResult Details()
{
var model = _studentRepository.GetById(1);
var viewModel = new StudentDetailsViewModel
{
Student = model,
PageTitle = "viewmodel里的页面标题"
};
return View(viewModel);
}

在View中使用

<!-- 这里注册的模型改成了ViewModel了 -->
@model StudyManagement.ViewModels.StudentDetailsViewModel
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<h1>强类型模型</h1>
<h2>@Model.PageTitle</h2>
<ul>
<li>@Model.Student.Id</li>
<li>@Model.Student.Name</li>
<li>@Model.Student.ClassName</li>
<li>@Model.Student.Email</li>
</ul>
</body>
</html>

View中使用循环

@model IEnumerable<StudyManagement.Models.Student>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<table border="1">
<tr>
<td>Id</td>
<td>姓名</td>
<td>班级</td>
<td>邮箱</td>
</tr>
@foreach (var student in Model)
{
<tr>
<td>@student.Id</td>
<td>@student.Name</td>
<td>@student.ClassName</td>
<td>@student.Email</td>
</tr>
}
</table>
</body>
</html>

布局视图 LayoutView

创建布局视图

<!DOCTYPE html>

<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>@ViewBag.Title</title>
</head>
<body>
<div>
@RenderBody()
</div> @RenderSection("Scripts", required: false)
</body>
</html>

渲染视图

@model IEnumerable<StudyManagement.Models.Student>
@{
Layout = "~/Views/Shared/_Layout.cshtml";
ViewBag.Title = "首页 学生列表";
}
<div></div>

视图节点 Section

在布局视图里渲染节点

@RenderSection("Scripts", required: false)

在普通视图里定义节点

@section Scripts{
<script>
document.write("hello");
</script>
}

视图开始 ViewStart

我的理解就是_ViewStart.cshtml文件所在目录下的每个视图文件开始渲染先执行这个文件的内容。一般直接放在Views目录下,全局生效,可以放在各个子文件夹下,这样可以覆盖全局的_ViewStart.cshtml

@{
Layout = "_Layout";
}

视图导入 ViewImports

用来导入命名空间、注册模型等等n多种操作。

生效机制和ViewStart差不多。

路由

  • 常规路由(传统路由)
  • 属性路由

常规路由

MapRoute方法中传入就好了。

// 自定义路由
app.UseMvc(route =>route.MapRoute("default",
"{controller=Home}/{action=Index}/{id?}"));

属性路由

比传统路由更加灵活,可以搭配传统路由使用。

即在控制器方法上添加路由注解,一个方法可以同时映射多个路由。

[Route("Home/Index")]
public IActionResult Index()
{
return View(_studentRepository.GetAll());
}

路由中也可以指定参数

[Route("test/{id?}")]
public IActionResult Details(int id = 1)
{
var model = _studentRepository.GetById(id);
var viewModel = new StudentDetailsViewModel
{
Student = model,
PageTitle = "viewmodel里的页面标题"
};
return View(viewModel);
}

可以直接在控制器类上加注解,[controller]/[action]

欢迎交流

交流问题请在微信公众号后台留言,每一条信息我都会回复哈~

Asp.Net Core学习笔记:入门篇的更多相关文章

  1. ASP.NET Core 学习笔记 第一篇 ASP.NET Core初探

    前言 因为工作原因博客断断续续更新,其实在很早以前就有想法做一套关于ASP.NET CORE整体学习度路线,整体来说国内的环境的.NET生态环境还是相对比较严峻的,但是干一行爱一行,还是希望更多人加入 ...

  2. ASP.NET Core 学习笔记 第二篇 依赖注入

    前言 ASP.NET Core 应用在启动过程中会依赖各种组件提供服务,而这些组件会以接口的形式标准化,这些组件这就是我们所说的服务,ASP.NET Core框架建立在一个底层的依赖注入框架之上,它使 ...

  3. PHP学习笔记--入门篇

    PHP学习笔记--入门篇 一.Echo语句 1.格式 echo是PHP中的输出语句,可以把字符串输出(字符串用双引号括起来) 如下代码 <?php echo "Hello world! ...

  4. PHP学习笔记 - 入门篇(5)

    PHP学习笔记 - 入门篇(5) 语言结构语句 顺序结构 eg: <?php $shoesPrice = 49; //鞋子单价 $shoesNum = 1; //鞋子数量 $shoesMoney ...

  5. PHP学习笔记 - 入门篇(4)

    PHP学习笔记 - 入门篇(4) 什么是运算符 PHP运算符一般分为算术运算符.赋值运算符.比较运算符.三元运算符.逻辑运算符.字符串连接运算符.错误控制运算符. PHP中的算术运算符 算术运算符主要 ...

  6. PHP学习笔记 - 入门篇(3)

    PHP学习笔记 - 入门篇(3) 常量 什么是常量 什么是常量?常量可以理解为值不变的量(如圆周率):或者是常量值被定义后,在脚本的其他任何地方都不可以被改变.PHP中的常量分为自定义常量和系统常量 ...

  7. ASP.NET Core 学习笔记 第三篇 依赖注入框架的使用

    前言 首先感谢小可爱门的支持,写了这个系列的第二篇后,得到了好多人的鼓励,也更加坚定我把这个系列写完的决心,也能更好的督促自己的学习,分享自己的学习成果.还记得上篇文章中最后提及到,假如服务越来越多怎 ...

  8. ASP.NET Core 学习笔记 第五篇 ASP.NET Core 中的选项

    前言 还记得上一篇文章中所说的配置吗?本篇文章算是上一篇的延续吧.在 .NET Core 中读取配置文件大多数会为配置选项绑定一个POCO(Plain Old CLR Object)对象,并通过依赖注 ...

  9. ASP.NET Core 学习笔记 第四篇 ASP.NET Core 中的配置

    前言 说道配置文件,基本大多数软件为了扩展性.灵活性都会涉及到配置文件,比如之前常见的app.config和web.config.然后再说.NET Core,很多都发生了变化.总体的来说技术在进步,新 ...

随机推荐

  1. Leetcode-剪枝

    51. N皇后 https://leetcode-cn.com/problems/n-queens/ n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击. ...

  2. P3419 [POI2005]SAM-Toy Cars / SP688 SAM - Toy Cars

    一道很妙的贪心题 题面 我们考虑当我们插入时会面临的两种情况 当地上的玩具,不满 \(k\) 个时,那我们直接放就可以了. 当满了 \(k\) 个的时候,我们就要从地上拿出一个来给当前的腾位置. 这就 ...

  3. randomatic

    下载 randomaticrandomatic 使用简单的字符序列生成指定长度的随机字符串.原generate-password. 请考虑下面这个项目的作者,Jon Schlinkert主演的,考虑项 ...

  4. lua 1.0 源码分析 -- 总结

    读完 lua1.0 的源码感触:1. 把复杂的代码写简单2. pack 的内存回收3. hash 实现简单,但是应该可以改进,看高版本的代码怎么实现4. lua 初始化环境做了什么,就是一组全局变量初 ...

  5. S3C2440 LCD驱动(FrameBuffer)实例开发<二>(转)

    开发板自带的LCD驱动是基于platform总线写的,所以如果要使其它的LCD能够在自己的开发板上跑起来,那么就先了解platform驱动的架构,下面简单记录下自己看platform驱动时体会,简单的 ...

  6. day27 Pyhton 面向对象02 类和对象的命名空间

    一.内容回顾 类:具有相同属性和方法的一类事务 # 描述一类事务轮廓的一个机制 #商品/用户/店铺 对象/实例: 对象(实例)就是类的实例化 # 对象就是类的一个具体的表现 #某一件特定的商品/某个人 ...

  7. 写给前端同学的C++入门教程(一):概述和环境搭建

    说明:本人是前端er,因为最近对 UE4(一个游戏开发引擎)产生了兴趣,而这个引擎源开发游戏时需要用到 C++ ,所以就开始入坑 C++ 了.现将自己学习 C++ 的笔记整理并分享出来,以便一些想入门 ...

  8. pytest使用小结

    一.pytest简洁和好处 自动发现测试用例 testloader 断言方便 ,自定义错误提示 assert 正则匹配 灵活运行指定的测试用例,指定模块,制定测试类,测试用例 -k 标签化,回归 正向 ...

  9. 解了这14道C语言谜题后,所有人都失声了!我来带你深入了解C!

    本文展示了14个C语言的迷题以及答案,代码应该是足够清楚的,而且有相当的一些例子可能是我们日常工作可能会见得到的.通过这些迷题,希望你能更了解C语言. 如果你不看答案,不知道是否有把握回答各个谜题?让 ...

  10. docker-阿里云加速

    系统版本 centos7 阿里云登录 ->容器镜像服务->镜像加速器 复制下面的直接执行即可     sudo mkdir -p /etc/docker sudo tee /etc/doc ...