.NET-5..NET Core Web API


前言

参考文献
简单的Web API 应用案例
Web API身份验证token
Web API_哔哩哔哩_bilibili--github.com
- yi念之间 - 博客园 (cnblogs.com)>

Swagger/OpenAPI
参考文献

  1. Swagger/OpenAPI
  2. 使用 Swagger 文档改进开发人员的 API 体验

Web API 理论部分

//注意的小细节
1. 如果控制器中存在一个没有添加[HttpGet]、[HttpPost]等的public方法,Swagger就会报错,
可以用[ApiExplorerSettings(IgnoreApi = true)]
2. //给没有配置httpmethod的action添加默认操作
app.AutoHttpMethodIfActionNoBind();
3.HTTP传递参数的三种方式
- URL:适合定位;长度限制。
- QueryString:灵活;长度限制。
- 请求报文体:灵活;长度不限制;不支持GET、Delete。
3.常用的特性
[Route("api/[controller]/[action]")]
[HttpGet("{id}")] public Person GetPerson(long id);
[Produces("application/json")]//声明控制器的操作支持 application/json 的响应内容类型
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
app.MapGet("/todos/{id}", ([FromRoute] int id) => new Todo { Id = id });
Get([FromQuery]int id)  https://localhost:7082/WeatherForecast?id=1


4.返回类型
//ActionResult<T> 类型。 ASP.NET Core 自动将对象序列化为 JSON
Ok("ok");此返回类型的响应代码为 200 OK
Content("ok")
BadRequest("ok")
NotFound()//返回 404 状态NotFound错误代码。
NoContent()


[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.
https://www.cnblogs.com/gygtech/p/14677658.html

1. Web API两种风格:面向过程(RPC)、面向REST(REST)

RPC:业务驱动,自然。
REST:要求开发人员对REST原则更了解、并且有更多的设计能力

RPC:“控制器/操作方法“的形式把服务器端的代码当成方法去调用。把HTTP当成传输数据的通道,不关心HTTP谓词。通过QueryString、请求报文体给服务器传递数据。状态码。比如:/Persons/GetAll、/Persons/GetById?id=8、/Persons/Update、/Persons/DeleteById/8;

REST:按照HTTP的语义来使用HTTP协议:
1、URL用于资源的定位:/user/888、/user/888/orders;
2、HTTP谓词:GET、POST(新增)、PUT(整体更新)、DELETE、PATCH(局部更新)等;
3、什么是“幂等”,举例?DELETE、PUT、GET是幂等的,POST不幂等;
4、GET的响应可以被缓存;
5、服务器端要通过状态码来反映资源获取的结果:404、403(没有权限)、201(新增成功)。

//这是rest风格
[Route("api/[controller]")]
public class PersonsController : ControllerBase
{
	[HttpGet]
	public IEnumerable<Person> GetPersons();	
	[HttpGet("{id}")]
	public Person GetPerson(long id);
	[HttpPut("{id}")]
	public void UpdatePerson(long id, Person person);
	[HttpPost]
	public void SavePerson(Person person);
	[HttpDelete("{id}")]
	public void DeletePerson(long id);
}
//REST的优缺点
1、通过URL对资源定位,语义更清晰;
2、通过HTTP谓词表示不同的操作,接口自描述;
3、可以对GET、PUT、DELETE请求进行重试;
4、可以用GET请求做缓存;
5、通过HTTP状态码反映服务器端的处理结果,统一错误处理机制。
6、网关等可以分析请求处理结果。
//缺点
1、真实系统中的资源非常复杂,很难清晰地进行资源的划分,对技术人员的业务和技术水平要求高。
2、不是所有的操作都能简单地对应到确定的HTTP谓词中。
3、系统的进化可能会改变幂等性。
4、通过URL进行资源定位不符合中文用户的习惯。
5、HTTP状态码个数有限。
6、有些环节会篡改非200响应码的响应报文。
7、有的客户端不支持PUT、DELETE请求。

2.Swagger/OpenAPI

参考文献

  1. Swagger/OpenAPI
  2. 使用 Swagger 文档改进开发人员的 API 体验

OpenAPI 是一种规范。
Swagger 是一种使用 OpenAPI 规范的工具。 例如,OpenAPIGenerator 和 SwaggerUI。

Swashbuckle入门使用

1.添加NeGet包
Swashbuckle.AspNetCore
2.添加并配置 Swagger 中间件
builder.Services.AddSwaggerGen();//服务
if (app.Environment.IsDevelopment())//生成的 JSON 文档和 Swagger UI 提供服务
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

3.拓展
项目文件 .csproj添加
<PropertyGroup>
 .....
  	<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
builder.Services.AddSwaggerGen(options =>
{
    options.SwaggerDoc("v1", new OpenApiInfo
    {
        Version = "v1",
        Title = "ToDo API",
        Description = "An ASP.NET Core Web API for managing ToDo items",
        TermsOfService = new Uri("https://example.com/terms"),
        Contact = new OpenApiContact
        {
            Name = "Example Contact",
            Url = new Uri("https://example.com/contact")
        },
        License = new OpenApiLicense
        {
            Name = "Example License",
            Url = new Uri("https://example.com/license")
        }
    });
    //反射用于生成与 Web API 项目相匹配的 XML 文件名
     var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
    options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
});
//在控制器上添加,会生成相应的注释和帮助文档
[Produces("application/json")]//声明控制器的操作支持 application/json 的响应内容类型
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
ii.注释
/// <summary>
/// 实验
/// </summary>
/// <param name="item"></param>
/// <returns>A newly created TodoItem</returns>
/// <remarks>
/// Sample request:
///
///     POST /Todo
///     {
///        "id": 1,
///        "name": "Item #1",
///        "isComplete": true
///     }
///
/// </remarks>
/// <response code="201">Returns the newly created item</response>
/// <response code="400">If the item is null</response>

Web API 实践部分

1. web api 尝试? 、例子

[HttpPost]
public string SaveNote(SaveNoteRequest req)
 {
     string filename = $"./asset/{req.Title}.txt";//建个文件夹
     System.IO.File.WriteAllText(filename, req.Content);
     return filenam+req.ToString()e;
 }
 public record SaveNoteRequest(string Title,string Content);


// 推荐用ActionResult<T>,它支持类型转换
[HttpGet]
public ActionResult<SaveNoteRequest> GetPerson(int id)
{
    if (id <= 0)
        return BadRequest("id必须是正数");
    else if (id == 1)
        return new SaveNoteRequest(1, "ccc", "ccc内容");
    else if (id == 2)
        return new SaveNoteRequest(2, "ddd", "ddd内容");
    else
        return NotFound("不存在");//自定义消息
}

//捕捉URL占位符
1、在[HttpGet]、[HttpPost]等中使用占位符,比如{schoolName},
/aaa/GetAll/
[HttpGet("aaa/{paramName}")]
2、捕捉的值会被自动赋值给Action中同名的参数;如果名字不一致,可以用[FromRoute(Name="名字")

二、 简单的Web API 应用案例

ASP.NET Core 中的 CRUD 操作

  1. 运行以下命令以创建 Models 文件夹
  2. 将以下代码添加到 Models/Pizza.cs 以定义披萨
  3. 运行以下命令以创建 Services 文件夹//添加数据服务
  4. 将以下代码添加到 Services/PizzaService.cs,
  5. 选择 Controllers 文件夹,并添加名为 PizzaController.cs 的新文件
//Pizza.cs
namespace ContosoPizza.Models;

public class Pizza
{
    public int Id { get; set; }
    public string? Name { get; set; }
    public bool IsGlutenFree { get; set; }
}
//PizzaService.cs
using ContosoPizza.Models;
namespace ContosoPizza.Services;

public static class PizzaService
{
    static List<Pizza> Pizzas { get; }
    static int nextId = 3;
    static PizzaService()
    {
        Pizzas = new List<Pizza>
        {
            new Pizza { Id = 1, Name = "Classic Italian", IsGlutenFree = false },
            new Pizza { Id = 2, Name = "Veggie", IsGlutenFree = true }
        };
    }

    public static List<Pizza> GetAll() => Pizzas;

    public static Pizza? Get(int id) => Pizzas.FirstOrDefault(p => p.Id == id);

    public static void Add(Pizza pizza)
    {
        pizza.Id = nextId++;
        Pizzas.Add(pizza);
    }

    public static void Delete(int id)
    {
        var pizza = Get(id);
        if(pizza is null)
            return;

        Pizzas.Remove(pizza);
    }

    public static void Update(Pizza pizza)
    {
        var index = Pizzas.FindIndex(p => p.Id == pizza.Id);
        if(index == -1)
            return;

        Pizzas[index] = pizza;
    }
}

//PizzaController.cs
using ContosoPizza.Models;
using ContosoPizza.Services;
using Microsoft.AspNetCore.Mvc;

namespace ContosoPizza.Controllers;

[ApiController]
[Route("[controller]")]
public class PizzaController : ControllerBase
{
    public PizzaController()
    {
    }

    // GET all action
    [HttpGet]
	public ActionResult<List<Pizza>> GetAll() =>
	    PizzaService.GetAll();

    // GET by Id action
    [HttpGet("{id}")]
	public ActionResult<Pizza> Get(int id)
	{
	    var pizza = PizzaService.Get(id);
	
	    if(pizza == null)
	        return NotFound();
	
	    return pizza;
	}

    // POST action
    [HttpPost]
	public IActionResult Create(Pizza pizza)
	{            
	    PizzaService.Add(pizza);
	    return CreatedAtAction(nameof(Create), new { id = pizza.Id }, pizza);
	}

    // PUT action
    [HttpPut("{id}")]
	public IActionResult Update(int id, Pizza pizza)
	{
	    if (id != pizza.Id)
	        return BadRequest();
	           
	    var existingPizza = PizzaService.Get(id);
	    if(existingPizza is null)
	        return NotFound();
	   
	    PizzaService.Update(pizza);           
	   
	    return NoContent();
	}

    // DELETE action
    [HttpDelete("{id}")]
	public IActionResult Delete(int id)
	{
	    var pizza = PizzaService.Get(id);
	   
	    if (pizza is null)
	        return NotFound();
	       
	    PizzaService.Delete(id);
	   
	    return NoContent();
	}
}

三、 简单参考

超重点
参考

 [HttpPost]
[Consumes("application/json")]
public IActionResult PostJson(IEnumerable<int> values) =>
Ok(new { Consumes = "application/json", Values = values });
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);
    if (todoItem == null){return NotFound();}
    return todoItem;
}
// GET: api/TodoItems
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
{
    return await _context.TodoItems
        .Select(x => ItemToDTO(x))
        .ToListAsync();
}

ApiController 属性
[ApiController] 属性可应用于控制器类,以启用下述 API 特定的固定行为:

属性路由要求
自动 HTTP 400 响应
绑定源参数推理
Multipart/form-data 请求推理
错误状态代码的问题详细信息

1.操作不可通过由UseEndpoints、UseMvc或UseMvcWithDefaultRoute定义的常规路由进行访问。
2.使模型验证错误自动触发 HTTP 400 响应。

//pet.cs
public class Pet
{
    public int Id { get; set; }
    [Required]
    public string? Breed { get; set; }
    public string? Name { get; set; }
    [Required]
    public PetType PetType { get; set; }
}

public enum PetType
{
    Dog = 0,
    Cat = 1
}
//PetsController.cs
#region snippet_Inherit
[Produces(MediaTypeNames.Application.Json)]
[Route("[controller]")]
public class PetsController : MyControllerBase
#endregion
{
    private static readonly List<Pet> _petsInMemoryStore = new List<Pet>();

    public PetsController()
    {
        if (_petsInMemoryStore.Count == 0)
        {
            _petsInMemoryStore.Add(
                new Pet 
                { 
                    Breed = "Collie", 
                    Id = 1, 
                    Name = "Fido", 
                    PetType = PetType.Dog 
                });
        }
    }

    [HttpGet]
    public ActionResult<List<Pet>> GetAll() => _petsInMemoryStore;

    [HttpGet("{id}")]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public ActionResult<Pet> GetById(int id)
    {
        var pet = _petsInMemoryStore.FirstOrDefault(p => p.Id == id);

        #region snippet_ProblemDetailsStatusCode
        if (pet == null)
        {
            return NotFound();
        }
        #endregion

        return pet;
    }

    #region snippet_400And201
    [HttpPost]
    [ProducesResponseType(StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public ActionResult<Pet> Create(Pet pet)
    {
        pet.Id = _petsInMemoryStore.Any() ? 
                 _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
        _petsInMemoryStore.Add(pet);

        return CreatedAtAction(nameof(GetById), new { id = pet.Id }, pet);
    }
    #endregion
}
//--------------

posted @ 2022-04-27 18:46  cactus9  阅读(59)  评论(0编辑  收藏  举报