ASP.NET Core 3 高级编程(第8版) 学习笔记 03

本篇介绍原书的第 18 章,为 19 章 Restful Service 编写基础代码。本章实现了如下内容:

1)使用 Entity Framework Core 操作 Sql Server 数据库

2)Entity Framework Core 数据库迁移和使用种子数据的方法

3)使用中间件 (middleware) 来配置请求管道 (request pipeline)

Nuget 包

为了运行本章代码,需要下面的三个包:

复制代码
Microsoft.EntityFrameworkCore.SqlServer --version 3.1.1
Microsoft.EntityFrameworkCore.Design --version 3.1.1
Microsoft.EntityFrameworkore.Tool --version 3.1.1

数据模型

创建 Products, Category 和 Suppliers 三个实体模型:

cs 复制代码
namespace WebApp.Models
{
    public class Category
    {
        public long CategoryId { get; set; }
        public string Name { get; set; }

        public IEnumerable<Product> Products { get; set; }
    }
}
cs 复制代码
namespace WebApp.Models
{
    public class Supplier
    {
        public long SupplierId { get; set; }
        public string Name { get; set; }
        public string City { get; set; }

        public IEnumerable<Product> Products { get; set; }
    }
}
cs 复制代码
namespace WebApp.Models
{
    public class Product
    {
        public long ProductId { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }  

        public long CategoryId { get; set; }
        public Category Category { get; set; }

        public long SupplierId { get; set; }
        public Supplier Supplier { get; set; }  
    }
}

创建 DbContext 类

cs 复制代码
using Microsoft.EntityFrameworkCore;

namespace WebApp.Models
{
    public class DataContext : DbContext
    {
        public DataContext(DbContextOptions<DataContext> opts) : base(opts) { }

        public DbSet<Product> Products { get; set; }
        public DbSet<Category> Categories { get; set; }
        public DbSet<Supplier> Suppliers { get; set; }
    }
}

种子数据

cs 复制代码
using Microsoft.EntityFrameworkCore;
using System.Linq;

namespace WebApp.Models
{
    public class SeedData
    {
        public static void SeedDatabase(DataContext context)
        {
            context.Database.Migrate();
            // 只有在空的时候才填充数据
            if (context.Products.Count() == 0 && context.Suppliers.Count() == 0 && context.Categories.Count() == 0) {

                // 供应商
                var s1 = new Supplier
                {
                    Name = "Splash Dudes",
                    City = "San Jose"
                };

                var s2 = new Supplier
                {
                    Name = "Soccer Town",
                    City = "Chicago"
                };

                var s3 = new Supplier 
                { 
                    Name = "Chess Co",
                    City = "New York"
                };

                // Category
                var c1 = new Category { Name = "Watersports" };
                var c2 = new Category { Name = "Soccer" };
                var c3 = new Category { Name = "Chess" };

                context.Products.AddRange(
                   new Product { Name = "Kayak", Price = 275, Category = c1, Supplier = s1} ,
                   new Product { Name = "LifeJacket", Price = 48.95m, Category = c1, Supplier = s1} , 
                   new Product { Name = "Soccer ball", Price = 19.50m, Category= c2, Supplier = s2} ,
                   new Product { Name = "Corner Flags", Price = 34.95m, Category= c2, Supplier = s2} ,
                   new Product { Name = "Stadium", Price = 79500, Category= c2, Supplier = s2} ,
                   new Product { Name = "Thinking Cap", Price = 16, Category= c3, Supplier = s3} ,
                   new Product { Name = "Unsteady Chair", Price = 29.95m, Category= c3, Supplier = s3} ,
                   new Product { Name = "Human Chess Board", Price = 75, Category= c3, Supplier = s3} ,
                   new Product { Name = "Bling-Bling King", Price = 1200, Category= c3, Supplier = s3} 
                );

                context.SaveChanges();
            }
        }
    }
}

数据库连接字符串

使用 Sql Server LocalDB,将数据库连接字符串写在 appsettings.json 文件。

复制代码
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information",
      "Microsoft.EntityFrameworkCore": "Information"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings" : {"ProductConnection" : "Server=(localdb)\\MSSQLLocalDB;Database=Products;MultipleActiveResultSets=True"}
}

配置 Entity Framework Core

在 Startup.cs 的 Configure() 方法中进行配置:

cs 复制代码
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using WebApp.Models;

namespace WebApp
{
    public class Startup
    {
        public Startup(IConfiguration config)
        {
            Configuration = config;
        }

        public IConfiguration Configuration { get; set; }

        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<DataContext>(opts =>
            {
                opts.UseSqlServer(Configuration["ConnectionStrings:ProductConnection"]);
                //opts.EnableSensitiveDataLogging(true);
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, DataContext context)
        {         

            if (env.IsDevelopment()) {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();
            
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Hello World!");
                });
            });

            SeedData.SeedDatabase(context);
        }
    }
}

注意:Configure() 方法在默认代码的基础上增加了 DbContext 参数,目的是启动的时候自动运行向数据库添加种子数据。

数据库迁移

打开 Package Manager Console (Tools > Nuget Package Manager > Package Manager Console),运行下面两个命令:

复制代码
Add-migration initDatabae
update-database

Add-migration 命令将创建迁移脚本

update-database 将未提交的变化提交到数据库。

运行之后,使用 SQL Server Object Explorer (View > SQL Server Object Explore)可以看到,数据库和表都已经正确创建。

使用中间件配置请求管道

希望实现的效果是 Http Get 请求 /test 能返回三张表的数据条数。

创建 TestMiddleware 中间件:

cs 复制代码
using Microsoft.AspNetCore.Http;
using System.Linq;
using System.Threading.Tasks;
using WebApp.Models;

namespace WebApp
{
    public class TestMiddleware
    {
        private RequestDelegate nextDelegate;

        public TestMiddleware(RequestDelegate nextDelegate)
        {
            this.nextDelegate = nextDelegate;
        }

        public async Task Invoke(HttpContext context, DataContext dataContext)
        {
            if (context.Request.Path == "/test") {
                await context.Response.WriteAsync($"There are {dataContext.Products.Count()} prodcts.\n");
                await context.Response.WriteAsync($"There are {dataContext.Categories.Count()} categories.\n");
                await context.Response.WriteAsync($"There are {dataContext.Suppliers.Count()} suppliers.\n");
            } else {
                await nextDelegate(context);
            }
        }
    }
}

在 Startup.cs 文件中配置中间件。

cs 复制代码
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using WebApp.Models;

namespace WebApp
{
    public class Startup
    {
        public Startup(IConfiguration config)
        {
            Configuration = config;
        }

        public IConfiguration Configuration { get; set; }

        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<DataContext>(opts =>
            {
                opts.UseSqlServer(Configuration["ConnectionStrings:ProductConnection"]);
                //opts.EnableSensitiveDataLogging(true);
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, DataContext context)
        {         

            if (env.IsDevelopment()) {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();
            app.UseMiddleware<TestMiddleware>();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Hello World!");
                });
            });

            SeedData.SeedDatabase(context);
        }
    }
}

源码

pro asp.net core 3 notes: 《ASP.NET Core 3高级编程(第8版)》学习笔记

相关推荐
302wanger1 小时前
【阅读笔记】当AI拿走一切之后
笔记
疯狂打码的少年2 小时前
【数据结构】串(字符串):基本概念与存储
数据结构·笔记
for_ever_love__2 小时前
python基础语法学习: 数据容器
windows·python·学习
云空3 小时前
《电子专业完整学习路线图(分两套:本科四年版 / 零基础自学速成版)》
科技·学习·学习方法·高考
min(a,b)3 小时前
学习第16天:LangGraph 与 Agent 工作流编排
学习
woshihuanglaoshi3 小时前
鸿蒙技术进阶全景高级成长体系:从初中级到架构师的技能树/学习路径/项目实战/认证体系系统性方法论
学习·华为·harmonyos
AI即插即用3 小时前
即插即用系列 | IEEE TMI PLG-HN:原型学习引导的 CNN-Transformer 混合网络,攻克乳腺肿瘤分割难题
人工智能·深度学习·神经网络·学习·目标检测·cnn·transformer
Hotchip_MEMS4 小时前
TWS耳机微米级较量:超薄LGA封装如何助力MEMS麦克风小型化?
人工智能·笔记·物联网·电脑
Ztt6666666665 小时前
金泉方壶四面端正,月白釉却把棱角放柔了
经验分享·笔记·其他·百度·微信公众平台
for_ever_love__5 小时前
python基础语法学习: 变量, 输入输出, 运算符
网络·python·学习