Asp-Net-Core Study Notes: 1. Getting Started with MVC
Asp.Net Core Learning Study notes based on .Net Core 2.2. Basics Automatically check for code updates and reload the server like Django (so convenient) dotnet watch run Hosting Settings Set the AspNetCoreHostingModel property of the project file. PropertyGroup TargetFrameworknetcoreapp2.2/TargetFramework Asp
目录42 个章节
Asp.Net Core Learning
Study notes based on .Net Core 2.2.
Basics
Automatically check for code updates and reload the server like Django (so convenient)
dotnet watch run
Hosting Settings
Set the AspNetCoreHostingModel property of the project file.
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
</PropertyGroup>
- InProcess: Hosted using the IIS server
- OutOfProcess: Hosted using the built-in Kestrel server
Getting Started with Middleware
- Can be accessed and requested at the same time
- Can process a request and then pass it to the next middleware
- Can process a request and then short-circuit the pipeline
- Can send out a response
- Middleware is executed in the order it is added
Introduce Asp.Net Core's built-in logging component by adding the parameter ILogger<Startup> logger in Configure.
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: 处理请求,生成响应");
});
}
Log output: (you can see the execution process of the three middleware)
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
Static File Support
All static files are under the wwwroot directory
First
// 设置默认文件
// 不设置的话,默认就是index.html/default.html这几个
var defaultFileOpinions = new DefaultFilesOptions();
defaultFileOpinions.DefaultFileNames.Clear();
defaultFileOpinions.DefaultFileNames.Add("test.html");
// 添加默认文件中间件,必须在UseStaticFiles之前注册
app.UseDefaultFiles(defaultFileOpinions);
// 添加静态文件中间件
app.UseStaticFiles();
DirectoryBrowser Middleware
You can browse the contents under wwwroot in the browser. Not recommended for use in production environments.
app.UseDirectoryBrowser();
FileServer Middleware
Integrates the functionality of the three middleware UseDefaultFiles, UseStaticFiles, and UseDirectoryBrowser. Also not recommended for use in production environments.
var fileServerOpinions = new FileServerOptions();
fileServerOpinions.DefaultFilesOptions.DefaultFileNames.Clear();
fileServerOpinions.DefaultFilesOptions.DefaultFileNames.Add("test.html");
app.UseFileServer(fileServerOpinions);
Developer Exception Page
if (env.IsDevelopment())
{
var developerExceptionPageOptions = new DeveloperExceptionPageOptions();
// 显示代码行数
developerExceptionPageOptions.SourceCodeLineCount = 10;
app.UseDeveloperExceptionPage();
}
app.Run(async (context) =>
{
throw new Exception("自己抛出的异常");
});
Development Environment Variables
- Development: Development environment
- Staging: Staging (demo, simulation, temporary) environment
- Production: Production (live) environment
Ops:
- Use the
ASPNETCORE_ENVIRONMENTenvironment variable to set the development environment. - On the development machine, set environment variables in the
launchSettings.jsonfile. - In Staging and Production environments, try to set environment variables at the operating system level.
- Use the
IHostEnvironmentservice to access the runtime environment - Besides the standard environments, custom environments (UAT, QA, etc.) are also supported
Introducing the MVC Framework
First, add the MVC service.
public void ConfigureServices(IServiceCollection services)
{
// 单纯引入核心MVC服务,只有核心功能
services.AddMvcCore();
// 一般用这个,功能多
services.AddMvc();
}
Add Middleware
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 routing rule: /控制器名称/方法名称, (case-insensitive)
For example, the route in the following example is: /home/index
HomeController code:
public class HomeController : Controller
{
public string Index()
{
return "home controller";
}
}
A Preliminary Look at Models and Dependency Injection
Define the Model
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public string ClassName { get; set; }
public string Email { get; set; }
}
Define the Interface
public interface IStudentRepository
{
Student GetById(int id);
void Save(Student student);
}
Implement the Interface
The database is not connected yet; define a class with mock data
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();
}
Register Dependency Injection
There are three ways to register services in the Asp.Net Core dependency injection container
- AddSingleton
- AddTransient
- AddScoped
Advantages of dependency injection
- Low coupling
- High testability, making unit testing more convenient
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// 注册依赖注入,将实现类与接口绑定
services.AddSingleton<IStudentRepository, MockStudentRepository>();
}
Using Dependency Injection in the Model
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));
}
}
Getting Started with Controllers
Content Negotiation
Use the ObjectResult return type in controller methods to support content negotiation, returning data based on request header parameters,
// 支持内容格式协商
public ObjectResult Details(int id)
{
return new ObjectResult(_studentRepository.GetById(id));
}
For example:
Accept: application/xml
will return xml format. Note: an xml serializer also needs to be added.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
// 注册XML序列化器
.AddXmlSerializerFormatters();
}
Getting Started with Views
Methods for Passing Data from the Controller to the View
The first two are both weakly typed
- ViewData
- ViewBag
- Strongly typed views
ViewData
- Weakly typed dictionary object
- Uses string-type keys to store and query
- Dynamically resolved at runtime
- No IntelliSense, and no type checking at compile time
Usage:
ViewData["Title"] = "学生视图";
ViewData["Model"] = model;
cshtml code:
<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 usage:
<h1>@ViewBag.PageTitle</h1>
<div>姓名:@ViewBag.Student.Name</div>
<div>班级:@ViewBag.Student.ClassName</div>
Strongly Typed Views
Pass the model to View() in the controller
public IActionResult GetView()
{
var model = _studentRepository.GetById(1);
return View(model);
}
Specify the model type in 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
Similar to DTO (Data Transfer Object)
Define a ViewModel
public class StudentDetailsViewModel
{
public Student Student { get; set; }
public string PageTitle { get; set; }
}
Modify the Controller
public IActionResult Details()
{
var model = _studentRepository.GetById(1);
var viewModel = new StudentDetailsViewModel
{
Student = model,
PageTitle = "viewmodel里的页面标题"
};
return View(viewModel);
}
Use in the 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>
Using Loops in the 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>
Layout View
Create a Layout View
<!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>
Render the View
@model IEnumerable<StudyManagement.Models.Student>
@{
Layout = "~/Views/Shared/_Layout.cshtml";
ViewBag.Title = "首页 学生列表";
}
<div></div>
View Section
Render a section in the layout view
@RenderSection("Scripts", required: false)
Define a section in a regular view
@section Scripts{
<script>
document.write("hello");
</script>
}
ViewStart
My understanding is that for every view file under the directory where the _ViewStart.cshtml file is located, the content of this file is executed first when rendering starts. It is generally placed directly in the Views directory so it takes effect globally, and can also be placed in various subfolders to override the global _ViewStart.cshtml.
@{
Layout = "_Layout";
}
ViewImports
Used to import namespaces, register models, and various other operations.
The way it takes effect is similar to ViewStart.
Routing
- Conventional routing (traditional routing)
- Attribute routing
Conventional Routing
Just pass it into the MapRoute method.
// 自定义路由
app.UseMvc(route =>route.MapRoute("default",
"{controller=Home}/{action=Index}/{id?}"));
Attribute Routing
More flexible than traditional routing, and can be used together with traditional routing.
That is, add routing attributes to controller methods; one method can map to multiple routes at the same time.
[Route("Home/Index")]
public IActionResult Index()
{
return View(_studentRepository.GetAll());
}
You can also specify parameters in the route
[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);
}
You can also add attributes directly on the controller class, [controller]/[action].
Welcome to Discuss
For questions, please leave a message on the WeChat official account backend; I will reply to every message~
- WeChat Official Account: 画星星高手
- Coding livestream: https://live.bilibili.com/11883038
- Zhihu: https://www.zhihu.com/people/dealiaxy
- Column: https://zhuanlan.zhihu.com/deali
- Jianshu: https://www.jianshu.com/u/965b95853b9f
_EOF_
Asp-Net-Core Study Notes: 1. Getting Started with MVC
- 本文作者:
- 程序设计实验室
- 版权声明:
- 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
相关文章
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 分钟
Asp-Net-Core学习笔记:4.Blazor-WebAssembly入门
本来今天开始是有其他的安排了,也没办法抽出那么多时间来学NetCore,不过我想做事情有始有终吧,除了gRPC还没跑起来之外,Blazor这部分也了解了一点。目前来说还不是很完善,真正的离线单页应用还处于预览版阶段。
2023-07-12 · Asp-Net-Core学习笔记 · 约 1 分钟
Asp-Net-Core学习笔记:WebApi开发实践
前言 用AspNetCore做Api开发也有一段时间了,正好年底在做总结,做一个WebApi开发实践笔记。 暂时想到的一些技术关键词,同时也作为本文的大纲,现在对这套技术体系的了解还不够深入,以后会持续更新这个Api开发实践~ 身份认证:JwtBearer 分页:X.PagedList 缓存 ResponseCache Redis:StackExchange.Redis 数据持久化 / ORM F
2022-07-04 · Asp-Net-Core学习笔记 · 约 1 分钟
Asp-Net-Core学习笔记:单元测试和集成测试
我在使用 AspNetCore 的这段时间内,看了很多开源项目和博客,发现各种 .Net 体系的新技术很多人都有关注和使用,但却很少有人关注测试。 测试是软件生命周期中的一个非常重要的阶段,对于保证软件的可靠性具有极其重要的意义。在应用程序的开发过程中,为了确保它的功能与预期一致,必须对其进行测试。这样做不仅能够确保功能正确执行,同时能够帮助开发人员尽早地发现并改正系统中所存在的缺陷(Bug),
2023-07-17 · Asp-Net-Core学习笔记 · 约 1 分钟
讨论
共 0 条加载评论中…