vscode 開發MVC項目記録


需要:

  • Visual Studio Code
  • 用于 Visual Studio Code 的 C#(最新版本)
  • .NET 6.0 SDK

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

上述命令添加:

  • EF Core 命令行接口 (CLI) 工具
  • aspnet-codegenerator 基架工具。
  • EF Core 的设计时工具
  • EF Core SQLite 提供程序将 EF Core 包作为依赖项进行安装。
  • 基架需要的包:Microsoft.VisualStudio.Web.CodeGeneration.Design 和 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#
(options =>
        options.UseSqlServer(builder.Configuration.GetConnectionString("ProductionMvcMovieContext")));
}
">var builder = WebApplication.CreateBuilder(args);

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

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

 

如果尚未安装 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 options)
            : base(options)
        {
        }

        public DbSet Movie { get; set; }
    }
}

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

依赖项注入

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

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

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

  • Visual Studio
  • Visual Studio Code
  • Visual Studio for Mac
C#
var builder = WebApplication.CreateBuilder(args);

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

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

Visual Studio

  • Visual Studio Code / Visual Studio for Mac
  • 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#
     new
                    {
                        Id = table.Column(type: "int", nullable: false)
                            .Annotation("SqlServer:Identity", "1, 1"),
                        Title = table.Column(type: "nvarchar(max)", nullable: true),
                        ReleaseDate = table.Column(type: "datetime2", nullable: false),
                        Genre = table.Column(type: "nvarchar(max)", nullable: true),
                        Price = table.Column(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");
            }
        }
    }
    ">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(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 方法中使用。

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

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

    可以为 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
    Details
    
    
        

    Movie


    @Html.DisplayNameFor(model => model.Title)
    @Html.DisplayFor(model => model.Title)
    @Html.DisplayNameFor(model => model.ReleaseDate)
    @Html.DisplayFor(model => model.ReleaseDate)
    @Html.DisplayNameFor(model => model.Genre)
    @Html.DisplayFor(model => model.Genre)
    @Html.DisplayNameFor(model => model.Price)
    @Html.DisplayFor(model => model.Price)
    Edit | Back to List ">@model MvcMovie.Models.Movie @{ ViewData["Title"] = "Details"; } <h1>Detailsh1> <div> <h4>Movieh4> <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 | Index">Back to Lista> 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 Index()
    {
        return View(await _context.Movie.ToListAsync());
    }
    

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

    CSHTML
    @model IEnumerable

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

    CSHTML
    Index
    
    

    Create New

    @foreach (var item in Model) { }
    @Html.DisplayNameFor(model => model.Title) @Html.DisplayNameFor(model => model.ReleaseDate) @Html.DisplayNameFor(model => model.Genre) @Html.DisplayNameFor(model => model.Price)
    @Html.DisplayFor(modelItem => item.Title) @Html.DisplayFor(modelItem => item.ReleaseDate) @Html.DisplayFor(modelItem => item.Genre) @Html.DisplayFor(modelItem => item.Price) Edit | Details | Delete
    ">@model IEnumerable @{ ViewData["Title"] = "Index"; } <h1>Indexh1> <p> <a asp-action="Create">Create Newa> 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
    | Details" asp-route-id="@item.Id">Details | Delete" asp-route-id="@item.Id">Delete td> tr> } tbody> table>

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

     
    C