这是一个基于微软官方文档的 Web Api 示例,同时示范了 ORM 工具 EF Core 的简单使用,控制器的各接口都采用异步操作以及LINQ语句,C Sharp 语法上有一些空和非空处理,这点像极了微软自家的 TypeScript。
假设我们需要一个用于展示项目待办事项的 BS 应用,它运行在公司内网的一台 PC 上,用在一个大屏设备上轮播展示那些亟需完成的工作项,这听上去很像一个工厂流水线上常见的场景。由于它只是用于展示“研发部门”未完成的项目工作项,不深度去考虑信息隔离、信息安全这些条件,作为后端只需要提供一个能够CRUD操作数据库的Web API,由于数据库使用 SQL Server ,ORM 自然就使用 EF Core ,在定义数据模型时采用了 Fluent 方式。
接着,我们准备相关的 CRUD 接口:
- 用于获取所有项目的接口 GetAllProjects
- 用于获取单个项目信息的接口 GetProject
- 用于获取单个项目所有的工作项的接口 GetProjectAllTodo
- 用于新建项目的接口 AddProject
- 用于新建项目工作项的接口 AddProjectTodo
- 用于修改项目的接口 EditProject
- 用于修改项目工作项的接口 EditProjectTodo
- 用于删除项目的接口 DeleteProject
- 用于删除项目工作项的接口 DeleteProjectTodo
从接口名称(路径)上看这并不是一个严格遵循 Restful 的 API,是的,它看上去有些 RPC风格,由于这仅仅是一个简单的案例,并没有专门为其写一个返回状态码和消息的函数,所以也省去了400派和200派的纠结。
IDE 毫无疑问使用 Visual Studio 2022,数据库使用 SQL Server 2022,先使用 Visual Studio 建立项目,先建立一个空白解决方案,比如命名成 ProjectTodoListSlideShow,再创建一个 ASP.NET Core Web API 项目,比如命名成 ProjectTodo,项目目录大致如下图:
添加一个控制器 ProjectTodoController ;
NuGet 包安装:
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Tools
项目根目录新建 Model 类
# Model.cs
using Microsoft.EntityFrameworkCore;
namespace ProjectTodo
{
public class ProjectTodoContext: DbContext
{
public DbSet<Project> Projects { get; set; }
public DbSet<ProjectTodo> ProjectTodos { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
string connStr = "Server=.;Database=project;Trusted_Connection=True;MultipleActiveResultSets=true;TrustServerCertificate=True";
optionsBuilder.UseSqlServer(connStr);
}
}
public class Project
{
public long Id { get; set; }
public string Name { get; set; } = null!;
public string? Description { get; set; }
public string? Owner { get; set; }
public DateTime Created { get; set; }
public string? Status { get; set; }
public List<ProjectTodo>? projectTodos { get; set; }
}
public class ProjectTodo
{
public long Id { get; set; }
public string Item { get; set; } = null!;
public string? Description { get; set; }
public string? Owner { get; set; }
public string? Remark { get; set; }
public DateTime Deadline { get; set; }
public DateTime Created { get; set; }
public string? Status { get; set; }
public long ProjectId { get; set; }
public Project? Project { get; set; }
}
}
项目根目录新建 Schema 类
# Schema.cs
namespace ProjectTodo
{
public class ProjectDTO
{
public long Id { get; set; }
public string Name { get; set; } = null!;
public string? Description { get; set; }
public string? Owner { get; set; }
public DateTime? Created { get; set; }
public string? Status { get; set; }
public ProjectDTO() { }
public ProjectDTO(Project project) => (Id, Name, Description, Owner, Created, Status) = (project.Id, project.Name, project.Description, project.Owner, project.Created, project.Status);
}
public class ProjectTodoDTO
{
public long Id { get; set; }
public string Item { get; set; } = null!;
public string? Description { get; set; }
public string? Owner { get; set; }
public string? Remark { get; set; }
public DateTime? Deadline { get; set; }
public DateTime? Created { get; set; }
public string? Status { get; set; }
public long ProjectId { get; set; }
public ProjectTodoDTO() { }
public ProjectTodoDTO(ProjectTodo projectTodo) => (Id, Item, Description, Owner, Remark, Deadline, Created, Status, ProjectId) = (projectTodo.Id, projectTodo.Item, projectTodo.Description, projectTodo.Owner, projectTodo.Remark, projectTodo.Deadline, projectTodo.Created, projectTodo.Status, projectTodo.ProjectId);
}
public class ProjectAddDTO
{
public long Id { get; set; }
public string Name { get; set; } = null!;
public string? Description { get; set; }
public string? Owner { get; set; }
public DateTime? Created { get; set; }
public string? Status { get; set; }
}
public class ProjectTodoAddDTO
{
public long Id { get; set; }
public string Item { get; set; } = null!;
public string? Description { get; set; }
public string? Owner { get; set; }
public string? Remark { get; set; }
public DateTime? Deadline { get; set; }
public DateTime? Created { get; set; }
public string? Status { get; set; }
public long ProjectId { get; set; }
}
public class ProjectEditDTO
{
public long Id { get; set; }
public string Name { get; set; } = null!;
public string? Description { get; set; }
public string? Owner { get; set; }
public DateTime? Created { get; set; }
public string? Status { get; set; }
}
public class ProjectTodoEditDTO
{
public long Id { get; set; }
public string Item { get; set; } = null!;
public string? Description { get; set; }
public string? Owner { get; set; }
public string? Remark { get; set; }
public DateTime? Deadline { get; set; }
public DateTime? Created { get; set; }
public string? Status { get; set; }
public long ProjectId { get; set; }
}
}
Controllers/ProjectTodoController.cs 类代码如下:
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace ProjectTodo.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class ProjectTodoController : ControllerBase
{
[HttpGet]
public async Task<ActionResult<ProjectDTO>> GetAllProjects()
{
using ProjectTodoContext ctx = new ProjectTodoContext();
var projects = await ctx.Projects.Select(x=>new ProjectDTO(x)).ToListAsync();
return Ok(projects);
}
[HttpGet("{id}")]
public async Task<ActionResult<ProjectDTO>> GetProject(long id)
{
using ProjectTodoContext ctx = new ProjectTodoContext();
var project = await ctx.Projects.SingleOrDefaultAsync(x=>x.Id == id);
if (project == null)
{
return NotFound();
}
var projectDTO = new ProjectDTO(project);
return Ok(projectDTO);
}
[HttpGet("{id}")]
public async Task<ActionResult<List<ProjectTodoDTO>>> GetProjectAllTodos(long id)
{
using ProjectTodoContext ctx = new ProjectTodoContext();
var projectTodoDTOs = await ctx.ProjectTodos
.Where(t => t.ProjectId == id)
.Select(t => new ProjectTodoDTO(t))
.ToListAsync();
return Ok(projectTodoDTOs);
}
[HttpPost]
public async Task<ActionResult<ProjectAddDTO>> AddProject(ProjectAddDTO projectAddDTO)
{
using ProjectTodoContext ctx = new ProjectTodoContext();
var project = new Project
{
Name = projectAddDTO.Name,
Description = projectAddDTO.Description,
Owner = projectAddDTO.Owner,
Created = DateTime.Now,
Status = projectAddDTO.Status
};
ctx.Projects.Add(project);
await ctx.SaveChangesAsync();
projectAddDTO.Created = project.Created;
projectAddDTO.Id = project.Id;
return Ok(projectAddDTO);
}
[HttpPost]
public async Task<ActionResult<ProjectTodoAddDTO>> AddProjectTodo(ProjectTodoAddDTO projectTodoAddDTO)
{
using ProjectTodoContext ctx = new ProjectTodoContext();
var todo = new ProjectTodo
{
Item = projectTodoAddDTO.Item,
Description = projectTodoAddDTO.Description,
Owner = projectTodoAddDTO.Owner,
Remark = projectTodoAddDTO.Remark,
Deadline = (DateTime)projectTodoAddDTO.Deadline!,
Created = DateTime.Now,
Status = projectTodoAddDTO.Status,
ProjectId = projectTodoAddDTO.ProjectId
};
ctx.ProjectTodos.Add(todo);
await ctx.SaveChangesAsync();
projectTodoAddDTO.Created = todo.Created;
projectTodoAddDTO.Id = todo.Id;
return Ok(projectTodoAddDTO);
}
[HttpPut("{id}")]
public async Task<ActionResult<ProjectEditDTO>> EditProject(ProjectEditDTO projectEditDTO, long id)
{
using ProjectTodoContext ctx = new ProjectTodoContext();
var project = await ctx.Projects.FindAsync(id);
if (project == null)
{
return NotFound();
}
project.Name = projectEditDTO.Name;
project.Description = projectEditDTO.Description;
project.Owner = projectEditDTO.Owner;
project.Status = projectEditDTO.Status;
await ctx.SaveChangesAsync();
projectEditDTO.Id = project.Id;
projectEditDTO.Created = project.Created;
return Ok(projectEditDTO);
}
[HttpPut("{id}")]
public async Task<ActionResult<ProjectTodoEditDTO>> EditProjectTodo(ProjectTodoEditDTO projectTodoEditDTO, long id)
{
using ProjectTodoContext ctx = new ProjectTodoContext();
var todo = await ctx.ProjectTodos.FindAsync(id);
if (todo == null)
{
return NotFound();
}
todo.Item = projectTodoEditDTO.Item!;
todo.Description = projectTodoEditDTO?.Description;
todo.Owner = projectTodoEditDTO?.Owner;
todo.Remark = projectTodoEditDTO?.Remark;
todo.Status = projectTodoEditDTO?.Status;
if (projectTodoEditDTO?.Deadline != null)
{
todo.Deadline = projectTodoEditDTO.Deadline.Value;
}
await ctx.SaveChangesAsync();
projectTodoEditDTO!.Id = todo.Id;
projectTodoEditDTO.ProjectId = todo.ProjectId;
return Ok(projectTodoEditDTO);
}
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteProject(long id)
{
using ProjectTodoContext ctx = new ProjectTodoContext();
var project = await ctx.Projects.FindAsync(id);
if (project == null)
{
return NotFound();
}
ctx.Projects.Remove(project);
await ctx.SaveChangesAsync();
return NoContent();
}
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteProjectTodo(long id)
{
using ProjectTodoContext ctx = new ProjectTodoContext();
var todo = await ctx.ProjectTodos.FindAsync(id);
if (todo == null)
{
return NotFound();
}
ctx.ProjectTodos.Remove(todo);
await ctx.SaveChangesAsync();
return NoContent();
}
}
}
使用 SQL Server Management Studio 创建数据库 project ,再从 Visual Studio 上打开程序包管理控制器,分别输入:Add-Migration xxxx、Update-Database,通过 EF Core 建立数据库迁移,建表;
最后在 Visual Studio 上运行项目,在一个控制台应用被启动之后,项目也就跑起来了,上述代码中包含了异步操作,也有一些 LINQ操作,基本演示了一个 ASP.NET CORE WEB API的小项目。