首页 > 解决方案 > 如何使用接口在 API 控制器中单独编写业务逻辑作为助手类或处理程序

问题描述

我正在使用实体框架开发带有 API 控制器的 .net RESTful WebAPI 和动作。

它会自动生成控制器,所以我需要在控制器(EmployeeDetailController)中编写一个业务逻辑到助手(EmployeeDetailHandler)类并与接口(IEmployeeDetailHandler)连接。

因此需要连接Dbcontext到辅助类(EmployeeDetailHandler)而不依赖于控制器来使用 xunit 测试单元测试。

我如何编写处理程序类和控制器类?

这是我的控制器(带有动作的 API 控制器,使用实体框架)。

我需要通过将接口连接到控制器类来在帮助类中单独编写其中的逻辑。

[Route("api/[controller]")]
[ApiController]
public class EmployeeDetailController : ControllerBase
{
    private readonly AuthenticationContext _context;

    public EmployeeDetailController(AuthenticationContext context)
    {
        _context = context;
    }

    // GET: api/EmployeeDetail
    [HttpGet]
    public IEnumerable<EmployeeDetail> GetEmployeeDetails()
    {
        return _context.EmployeeDetails;
    }

    // GET: api/EmployeeDetail/5
    [HttpGet("{id}")]
    public async Task<IActionResult> GetEmployeeDetail([FromRoute] int id)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        var employeeDetail = await _context.EmployeeDetails.FindAsync(id);

        if (employeeDetail == null)
        {
            return NotFound();
        }

        return Ok(employeeDetail);
    }

    // PUT: api/EmployeeDetail/5
    [HttpPut("{id}")]
    public async Task<IActionResult> PutEmployeeDetail([FromRoute] int id, [FromBody] EmployeeDetail employeeDetail)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        if (id != employeeDetail.EId)
        {
            return BadRequest();
        }

        _context.Entry(employeeDetail).State = EntityState.Modified;

        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!EmployeeDetailExists(id))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }

        return NoContent();
    }

    // POST: api/EmployeeDetail
    [HttpPost]
    public async Task<IActionResult> PostEmployeeDetail([FromBody] EmployeeDetail employeeDetail)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        _context.EmployeeDetails.Add(employeeDetail);
        await _context.SaveChangesAsync();

        return CreatedAtAction("GetEmployeeDetail", new { id = employeeDetail.EId }, employeeDetail);
    }

    // DELETE: api/EmployeeDetail/5
    [HttpDelete("{id}")]
    public async Task<IActionResult> DeleteEmployeeDetail([FromRoute] int id)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        var employeeDetail = await _context.EmployeeDetails.FindAsync(id);
        if (employeeDetail == null)
        {
            return NotFound();
        }

        _context.EmployeeDetails.Remove(employeeDetail);
        await _context.SaveChangesAsync();

        return Ok(employeeDetail);
    }

    private bool EmployeeDetailExists(int id)
    {
        return _context.EmployeeDetails.Any(e => e.EId == id);
    }
  }

}

这是我的上下文类

public class AuthenticationContext : IdentityDbContext
{
    public AuthenticationContext(DbContextOptions options):base(options {}
    public DbSet<ApplicationUser> ApplicationUsers { get; set; }
    public DbSet<EmployeeDetail> EmployeeDetails { get; set; }
}

这是分贝模型

public class EmployeeDetail
{
    [Key]
    public int EId { get; set; }
    [Required]
    [Column(TypeName = "Nvarchar(100)")]
    public string EmployeeName { get; set; }
    [Required]
    [Column(TypeName = "Nvarchar(10)")]
    public string PhoneNo { get; set; }
    [Required]
    [Column(TypeName = "Nvarchar(10)")]
    public string BDay { get; set; }
    [Required]
    [Column(TypeName = "Nvarchar(10)")]
    public string Nic { get; set; }
}

Expect 是具有接口的相关处理程序类(服务/Hepler)。

标签: c#entity-frameworkasp.net-web-api

解决方案


单元测试适用于可以单独测试的少量代码。

忘记控制器,忘记 DbContext 并专注于您的业务逻辑。

您的控制器应该是进行模型验证并将数据传递到业务层的薄层,仅此而已。因此,您甚至不需要看它们。

因此,对业务逻辑进行单元测试。使用集成测试覆盖每个端点,以获取正确和不正确的模型等。

使用 Postman 之类的东西或其他任何允许这样做的东西来编排集成测试。

您显示的代码根本不适合单元测试。


推荐阅读