ASP.net Core 的RESTful应用

.tabset mean tabs.

使用Scaffolder模板创建api。

..\AppData\Roaming\NuGet\NuGet.Config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="api.nuget.org" value="https://api.nuget.org/v3/index.json" />
  </packageSources>
</configuration>

Create Project

vs code

dotnet new webapi -o MyWebApp --package Swashbuckle.AspNetCore:PackageVersion=6.2.3

add NuGet package

dotnet add package Microsoft.EntityFrameworkCore
dotnet add package MySql.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.Tools

Option NuGet package

Pomelo:

CLI> dotnet add package Pomelo.EntityFrameworkCore.MySql

Test

Browser

Models

建立Entity类:Supplier、Product、Category

DbContext

public class StorageBuyDbContext : DbContext
{
    public StorageBuyDbContext(DbContextOptions<StorageBuyDbContext> options) : base(options){}

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

add service

add connectiong string

"Data": {
  "StorageBuy": {
    "ConnectionString": "server=127.0.0.1; user id=DBAdmin; password=xbfirst; database=storagebuy; pooling=false; Convert Zero Datetime=True;"
  }
}

add mysql

services.AddDbContext<StorageBuyDbContext>(options =>
    options.UseMySQL(Configuration["Data:StorageBuy:ConnectionString"])
);

数据表

install ef-tool

dotnet tool install --global dotnet-ef

生成db执行文件

dotnet ef migrations add Initial

生成Table

dotnet ef database update

写入数据

seedData.cs

exec

Startup.cs

Configure方法中

SeedData.EnsurePopulated(app);

Part I 提取码: mmig

建立MCj

建立Controller

使用VS 2022 Scaffolder模板: VS2022 prj1

vs2022 pre2

配置路由

  • class
[ApiController]
[Route("api/[controller]")]
  • method
    以Get举例:
[HttpGet]

处理Data

所有数据:

return await _context.Products.ToListAsync();

指定数据:

var product = await _context.Products.FindAsync(id);

配置Json

忽略空值

services.Configure<JsonOptions>(
    opts =>
    {
        opts.JsonSerializerOptions.IgnoreNullValues = true;
    }
);

commit operator

指定操作方式(Table 3-1), 并指定源1(Table 3-2).
推荐使用PostMan来进行调试.

Table 3-1. HTTP Methods and Operations

HTTP Method Description
GET 从服务器获取数据
POST 向服务器提交新的Object
PUT 向服务器提交修改(整体)
DELETE 向服务器提交删除object.
PATCH 向服务器提交更新部分object.

Table 3-2. 源属性

Name Description
FromQuery Gets values from the query string.
FromRoute Gets values from route data.
FromForm Gets values from posted form fields.
FromBody Gets values from the request body.
FromHeader Gets values from HTTP headers.

PUT/POST/DELETE

  • 更新
_context.Entry(product).State = EntityState.Modified;
  • 添加
_context.Products.Add(product);
  • 移出
_context.Products.Remove(product);

Patch

在客户端patch时的操作码见Table3-3

Table 3-3. httpPatch操作码

Operation Notes
add Add a property or array element. For existing property: set value.
remove Remove a property or array element.
replace Same as remove followed by add at same location.
move Same as remove from source followed by add to destination using value from source.
copy Same as add to destination using value from source.
test Return success status code if value at path = provided value.

PM

Install-Package Microsoft.AspNetCore.Mvc.NewtonsoftJson

CLI

dotnet add package Microsoft.AspNetCore.Mvc.NewtonsoftJson

config

Startup

            services.AddControllers().AddNewtonsoftJson();

            services.Configure<MvcNewtonsoftJsonOptions>(opts => {
                opts.SerializerSettings.NullValueHandling
                = Newtonsoft.Json.NullValueHandling.Ignore;
            });

enjoin parameter

需要指定从哪里获取JSON, 普遍是FromBody,并用JsonPatchDocument解析JSON, 最后在方法里使用ApplyTo2

ModifyProduct(long id, [FromBody] JsonPatchDocument<Product> patchDoc)
patchDoc.ApplyTo(product);

patch method

        [HttpPatch("{id}")]
        public async Task<IActionResult> ModifyProduct(long id, [FromBody] JsonPatchDocument<Product> patchDoc)
        {
            var product = await _context.Products.FindAsync(id);

            if (product != null)
            {
                patchDoc.ApplyTo(product);

                await _context.SaveChangesAsync();
            }

            return Ok();
        }

Test Data

PowerShell

get

Invoke-WebRequest https://localhost:7255/api/products/1 | Select-Object Content

post

Invoke-RestMethod https://localhost:7255/api/products -Method POST -Body (@{ Name="Swimming Goggles";
Price=12.75; Category_id=1; Supplier_id=1} | ConvertTo-Json) -ContentType "application/json"
Invoke-RestMethod https://localhost:7255/api/products -Method POST -Body (@{ Name="Soccer Boots"; Price=89.99;
Category_id=2; Supplier_id=2} | ConvertTo-Json) -ContentType "application/json"
Invoke-RestMethod https://localhost:7255/api/products -Method POST -Body (@{ Name="Swim Buoy";
Price=19.99; Category_id=1; Supplier_id=1} | ConvertTo-Json) -ContentType "application/json"

update

Invoke-RestMethod https://localhost:7255/api/products/1 -Method PUT -Body (@{ Id=1; Name="Green Kayak";
Price=275; Category_id=1; Supplier_id=1} | ConvertTo-Json) -ContentType "application/json"

delete

Invoke-RestMethod https://localhost:7255/api/products/12 -Method DELETE

status code

Invoke-WebRequest https://localhost:7255/api/products/100 |Select-Object StatusCode

patch

allow tls1.24

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-RestMethod https://localhost:7255/api/products/1 -Method PATCH -Body '[{"op":"replace", "path":"Price", "value":"618.00"}]' -ContentType "application/json"

MyWebApp v6.0 提取码: tocx

Reference