一个ASP.NET Core Web Api示例

这是一个基于微软官方文档的 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的小项目。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注