Asp-Net-Core学习笔记:1.MVC入门篇
Asp.Net Core 学习 基于.Net Core 2.2版本的学习笔记。 常识 像Django那样自动检查代码更新,自动重载服务器(太方便了) dotnet watch run 托管设置 设置项目文件的AspNetCoreHostingModel属性。 PropertyGroup TargetFrameworknetcoreapp2.2/TargetFramework Asp
目录42 个章节
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]。
欢迎交流
交流问题请在微信公众号后台留言,每一条信息我都会回复哈~
_EOF_
Asp-Net-Core学习笔记:1.MVC入门篇
- 本文作者:
- 程序设计实验室
- 版权声明:
- 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
相关文章
Asp-Net-Core学习笔记:2.MVC视图、模型、持久化、文件、错误处理、日志
TagHelper 入门 优点:根据参数自动生成,不需要手写超链接,类似Django模板里面的url命令。 在ViewImport中添加TagHelper @addTagHelper *,Microsoft.AspNetCore.Mvc.TagHelpers 比如,链接TagHelper使用 a class=btn btn-outline-primary asp-controller=st
2022-08-12 · Asp-Net-Core学习笔记 · 约 1 分钟
Asp-Net-Core学习笔记:部署,早知道,还是docker,以及一点碎碎念
前言 AspNetCore技术栈在我们团队里的使用也有一段时间了,之前的部署方式一直是本地编译之后上传可执行文件到服务器,使用supervisor来管理进程这种很原始的方式。 参考之前的文章: 对于小项目来说尚可,够用,但是存在几个问题: 每次更新花费的时间太长了,无论是Framework-Dependent还是Self-Contained,都要上传很大的文件~ 更新的时候需要在superviso
2022-02-16 · Asp-Net-Core学习笔记 · 约 1 分钟
Asp-Net-Core学习笔记:3.使用SignalR实时通信框架开发聊天室
SignalR牛刀小试 在MVP杨老师的博客里看到这么个东西,我还以为是NetCore3才推出的新玩意,原来是已经有很多年的历史了,那看来还是比较成熟的一个技术了。 简介 SignalR是一个.NET Core/.NET Framework的开源实时框架,SignalR的可使用Web Socket, Server Sent Events 和 Long Polling作为底层传输方式。 Signal
2022-02-16 · Asp-Net-Core学习笔记 · 约 1 分钟
Asp-Net-Core学习笔记:5.构建和部署
从上次开始学习Asp.Net Core以来,一直都是玩一玩,还没有什么机会用来实战,最近公司有个新的小项目,于是我用Asp.Net Core来尝尝新,结果也是非常OK,熟悉之后开发效率感觉和Django基本没差。 那么进入正题,本文简单说说Asp.Net Core应用的构建和部署。 构建 构建是使用build命令,不过一般我们都用vs或者rider之类的IDE,应该比较少会用到这个命令: dotn
2022-02-16 · Asp-Net-Core学习笔记 · 约 1 分钟
讨论
共 0 条加载评论中…