Asp.Net Core學習筆記:入門篇

畫星星高手發表於2020-11-05

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]

歡迎交流

交流問題請在微信公眾號後臺留言,每一條資訊我都會回覆哈~

相關文章