vscode 開發MVC項目記録

需要:

dotnet new mvc -o MvcMovie                     新建MVC項目

code -r MvcMovie             加載csproj項目

dotnet dev-certs https --trust            信任證書

为了在开发环境中使用HTTPS,必须要生成加密证书。.net core提供了一个全局工具dotnet-dev-certs,使用该工具可在本地环境中创建自签名的证书。可以通过下面命令行安装该工具:

dotnet tool install -global dotnet-dev-certs

安装成功后,就可以用他自签名的证书。

-ep标志表示将生成证书导出的存储目录;

-p标志表示生成证书的密码。

可以使用-trust选项来信任生成的证书。

  • 启动 Kestrel
  • 启动浏览器。
  • 导航到 https://localhost:5001

Kestrel 是一个跨平台的适用于 Kestrel。 Kestrel 是包含在 ASP.NET Core 项目模板中的 Web 服务器,默认处于启用状态。

Kestrel 支持以下方案:

  • HTTPS
  • HTTP/2(在 macOS† 上除外)
  • 用于启用 WebSocket 的不透明升级
  • 用于获得 Nginx 高性能的 Unix 套接字

添加 NuGet 包

运行以下 .NET CLI 命令:

.NET CLI
dotnet tool uninstall --global dotnet-aspnet-codegenerator
dotnet tool install --global dotnet-aspnet-codegenerator
dotnet tool uninstall --global dotnet-ef
dotnet tool install --global dotnet-ef
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.EntityFrameworkCore.SQLite
dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
dotnet add package Microsoft.EntityFrameworkCore.SqlServer

上述命令添加:

使用基架工具为电影模型生成 CreateReadUpdate 和 Delete (CRUD) 页面。

在项目目录中打开命令窗口。 项目目录是包含 Program.cs 和 .csproj 文件的目录。

在 macOS 和 Linux 上,导出基架工具路径:

控制台
export PATH=$HOME/.dotnet/tools:$PATH

运行下面的命令:

.NET CLI
dotnet-aspnet-codegenerator controller -name MoviesController -m Movie -dc MvcMovieContext --relativeFolderPath Controllers --useDefaultLayout --referenceScriptLibraries -sqlite

下表详细说明了 ASP.NET Core 代码生成器参数:

参数说明
-M 模型的名称。
-dc 数据上下文。
--relativeFolderPath 用于创建文件的相对输出文件夹路径。
--useDefaultLayout|-udl 应为视图使用默认布局。
--referenceScriptLibraries 向“编辑”和“创建”页面添加 _ValidationScriptsPartial
-sqlite 标记来指定 DbContext 是否应使用 SQLite,而不是 SQL Server。

使用 h 开关获取 aspnet-codegenerator controller 命令方面的帮助:

.NET CLI
dotnet aspnet-codegenerator controller -h

将 SQLite 用于开发,将 SQL Server 用于生产

Program.cs 中突出显示的以下代码展示了如何在开发中使用 SQLite,以及在生产中使用 SQL Server。

C#
var builder = WebApplication.CreateBuilder(args);

if (builder.Environment.IsDevelopment())
{
    builder.Services.AddDbContext<MvcMovieContext>(options =>
        options.UseSqlite(builder.Configuration.GetConnectionString("MvcMovieContext")));
}
else
{
    builder.Services.AddDbContext<MvcMovieContext>(options =>
        options.UseSqlServer(builder.Configuration.GetConnectionString("ProductionMvcMovieContext")));
}

基架更新以下内容:

  • 在 Program.cs 文件中注册数据库上下文
  • 将数据库连接字符串添加到 appsettings.json 文件。

基架创建以下内容:

  • 电影控制器:Controllers/MoviesController.cs
  • “创建”、“删除”、“详细信息”、“编辑”和“索引”页面的 Razor 视图文件:Views/Movies/*.cshtml
  • 数据库上下文类:Data/MvcMovieContext.cs

自动创建这些文件和文件更新被称为“基架”。

尚且不能使用基架页面,因为该数据库不存在。 运行应用并选择“Movie App”链接会导致“无法打开数据库”或“无此类表: Movie”错误消息。

构建应用程序。 编译器会生成几个有关如何处理 null 值的警告。

若要消除可为空引用类型的警告,请从 MvcMovie.csproj 文件中删除以下行:

XML
<Nullable>enable</Nullable>


使用 EF Core 迁移功能来创建数据库。 迁移是可用于创建和更新数据库以匹配数据模型的一组工具。
 

如果尚未安装 dotnet ef,请安装它作为全局工具:

.NET CLI
  dotnet tool install --global dotnet-ef

有关 EF Core 的 CLI 的详细信息,请参阅 .Net CLI 的 EF Core 工具引用

运行以下 .NET CLI 命令:

.NET CLI
dotnet ef migrations add InitialCreate
dotnet ef database update
  • ef migrations add InitialCreate:生成 Migrations/{timestamp}_InitialCreate.cs 迁移文件。 InitialCreate 参数是迁移名称。 可以使用任何名称,但是按照惯例,会选择可说明迁移的名称。 因为这是首次迁移,所以生成的类包含用于创建数据库架构的代码。 数据库架构基于在 MvcMovieContext 类(位于 Data/MvcMovieContext.cs 文件中)中指定的模型。
  • ef database update:将数据库更新到上一个命令创建的最新迁移。 此命令在用于创建数据库的 Migrations/{time-stamp}_InitialCreate.cs 文件中运行 Up 方法。

检查生成的数据库上下文类和注册

对于 EF Core,使用模型执行数据访问。 模型由实体类和表示数据库会话的上下文对象构成。 上下文对象允许查询并保存数据。 数据库上下文派生自 Microsoft.EntityFrameworkCore.DbContext 并指定要包含在数据模型中的实体。

基架创建 Data/MvcMovieContext.cs 数据库上下文类:

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using MvcMovie.Models;

namespace MvcMovie.Data
{
    public class MvcMovieContext : DbContext
    {
        public MvcMovieContext (DbContextOptions<MvcMovieContext> options)
            : base(options)
        {
        }

        public DbSet<MvcMovie.Models.Movie> Movie { get; set; }
    }
}

前面的代码创建一个 DbSet<Movie> 属性,该属性表示数据库中的电影。

依赖项注入

ASP.NET Core 通过依赖关系注入 (DI) 生成。 服务(如数据库上下文)在 Program.cs 中向 DI 注册。 这些服务通过构造函数参数提供给需要它们的组件。

在 Controllers/MoviesController.cs 文件中,构造函数使用依赖关系注入将 MvcMovieContext 数据库上下文注入到控制器中。 数据库上下文将在控制器中的每个 CRUD 方法中使用。

基架在 Program.cs 中生成了以下突出显示的代码:

C#
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<MvcMovieContext>(options =>
    options.UseSqlite(builder.Configuration.GetConnectionString("MvcMovieContext")));

ASP.NET Core 配置系统读取“MvcMovieContext”数据库连接字符串。

检查生成的数据库连接字符串

基架向 appsettings.json 文件添加了一个连接字符串:

JSON
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "MvcMovieContext": "Data Source=MvcMovie.db"
  }
}}

进行本地开发时,ASP.NET Core 配置系统在 appsettings.json 文件中读取 ConnectionString 键。

InitialCreate 类

检查 Migrations/{timestamp}_InitialCreate.cs 迁移文件:

C#
using System;
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace MvcMovie.Migrations
{
    public partial class InitialCreate : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "Movie",
                columns: table => new
                {
                    Id = table.Column<int>(type: "int", nullable: false)
                        .Annotation("SqlServer:Identity", "1, 1"),
                    Title = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    ReleaseDate = table.Column<DateTime>(type: "datetime2", nullable: false),
                    Genre = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Movie", x => x.Id);
                });
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "Movie");
        }
    }
}

在上述代码中:

  • InitialCreate.Up 创建 Movie 表,并将 Id 配置为主键。
  • InitialCreate.Down 还原 Up 迁移所做的架构更改。

控制器中的依赖项注入

打开 Controllers/MoviesController.cs 文件并检查构造函数:

C#
public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

    public MoviesController(MvcMovieContext context)
    {
        _context = context;
    }

构造函数使用依赖关系注入将数据库上下文 (MvcMovieContext) 注入到控制器中。 数据库上下文将在控制器中的每个 CRUD 方法中使用。

测试“创建”页。 输入并提交数据。

测试“编辑”、“详细信息”和“删除”页 。

强类型模型和 @model 指令

在本教程之前的内容中,已经介绍了控制器如何使用 ViewData 字典将数据或对象传递给视图。 ViewData 字典是一个动态对象,提供了将信息传递给视图的方便的后期绑定方法。

MVC 提供将强类型模型对象传递给视图的功能。 此强类型方法启用编译时代码检查。 基架机制在 MoviesController 类和视图中传递了一个强类型模型。

检查 Controllers/MoviesController.cs 文件中生成的 Details 方法:

C#
// GET: Movies/Details/5
public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie
        .FirstOrDefaultAsync(m => m.Id == id);
    if (movie == null)
    {
        return NotFound();
    }

    return View(movie);
}

id 参数通常作为路由数据传递。 例如,https://localhost:5001/movies/details/1 的设置如下:

  • 控制器被设置为 movies 控制器(第一个 URL 段)。
  • 操作被设置为 details(第二个 URL 段)。
  • id 被设置为 1(最后一个 URL 段)。

id 可以通过查询字符串传入,如以下示例所示:

https://localhost:5001/movies/details?id=1

在未提供 id 值的情况下,id 参数可定义为可以为 null 的类型 (int?)。

Lambda 表达式会被传入 FirstOrDefaultAsync 方法以选择与路由数据或查询字符串值相匹配的电影实体。

C#
var movie = await _context.Movie
    .FirstOrDefaultAsync(m => m.Id == id);

如果找到了电影,Movie 模型的实例则会被传递到 Details 视图:

C#
return View(movie);

检查 Views/Movies/Details.cshtml 文件的内容:

CSHTML
@model MvcMovie.Models.Movie

@{
    ViewData["Title"] = "Details";
}

<h1>Details</h1>

<div>
    <h4>Movie</h4>
    <hr />
    <dl class="row">
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Title)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Title)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.ReleaseDate)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Genre)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Genre)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Price)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Price)
        </dd>
    </dl>
</div>
<div>
    <a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
    <a asp-action="Index">Back to List</a>
</div>

视图文件顶部的 @model 语句可指定视图期望的对象类型。 创建影片控制器时,将包含以下 @model 语句:

CSHTML
@model MvcMovie.Models.Movie

此 @model 指令允许访问控制器传递给视图的影片。 Model 对象为强类型对象。 例如,在 Details.cshtml 视图中,代码通过强类型的 Model 对象将每个电影字段传递给 DisplayNameFor 和 DisplayFor HTML 帮助程序。 Create 和 Edit 方法以及视图也传递一个 Movie 模型对象。

检查电影控制器中的 Index.cshtml 视图和 Index 方法。 请注意代码在调用 View 方法时是如何创建 List 对象的。 代码将此 Movies 列表从 Index 操作方法传递给视图:

C#
// GET: Movies
public async Task<IActionResult> Index()
{
    return View(await _context.Movie.ToListAsync());
}

创建电影控制器后,基架将以下 @model 语句包含在 Index.cshtml 文件的顶部:

CSHTML
@model IEnumerable<MvcMovie.Models.Movie>

@model 指令允许使用强类型的 Model 对象访问控制器传递给视图的电影列表。 例如,在 Index.cshtml 视图中,代码使用 foreach 语句通过强类型 Model 对象对电影进行循环遍历:

CSHTML
@model IEnumerable<MvcMovie.Models.Movie>

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </td>
            <td>
                <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
                <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
                <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

因为 Model 对象为强类型(作为 IEnumerable<Movie> 对象),因此循环中的每个项都被类型化为 Movie。 编译器还有一些其他优势,比如验证代码中使用的类型。

 
posted @ 2022-06-16 15:56  八风不动  阅读(180)  评论(0编辑  收藏  举报