曦远 (DealiAxy)一份私人的文字刊物

StarBlog
返回文章列表折页手记阅读全文
Asp-Net-Core学习笔记

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

曦远 (DealiAxy)约 36 分钟
目录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_ENVIRONMENT environment variable to set the development environment.
  • On the development machine, set environment variables in the launchSettings.json file.
  • In Staging and Production environments, try to set environment variables at the operating system level.
  • Use the IHostEnvironment service 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~

_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学习笔记:部署,早知道,还是docker,以及一点碎碎念

前言 AspNetCore技术栈在我们团队里的使用也有一段时间了,之前的部署方式一直是本地编译之后上传可执行文件到服务器,使用supervisor来管理进程这种很原始的方式。 参考之前的文章: 对于小项目来说尚可,够用,但是存在几个问题: 每次更新花费的时间太长了,无论是Framework-Dependent还是Self-Contained,都要上传很大的文件~ 更新的时候需要在superviso

2022-02-16 · Asp-Net-Core学习笔记 · 约 1 分钟

Asp-Net-Core学习笔记:身份认证入门

前言 过年前我又来更新了~ 我就说了最近不是在偷懒吧,其实这段时间还是有积累一些东西的,不过还没去整理…… 所以只能发以前没写完的一些笔记出来 就当做是温习一下啦 PS:之前说的红包封面我还没搞,得抓紧时间了 最近在准备搞一个我之前做的开源项目代码合集来做一期分享 两种常见的认证方式 先来看看两种常见的认证方式:基于token的认证和传统的session认证的区别。 session认证 我们知道,

2022-02-16 · Asp-Net-Core学习笔记 · 约 1 分钟

讨论

共 0 条

良言一句三冬暖,恶语伤人六月寒。

加载评论中…