首页 > 解决方案 > 将现有控制器操作转换为通用方法

问题描述

在我的 ASP.NET 5 Web API 项目中,我发现我的许多核心控制器都包含完全相同的 CRUD 方法。我发现我只是复制/粘贴代码并搜索和替换主要类型。警钟!这引发了这样的想法:如果可能,我想创建这些操作的通用实现以减少类似代码。这将有助于代码的可维护性等。

关于我如何做到这一点的任何建议?这是 VehicleType 使用的一个示例类。我的其他类(组织、国家等)非常相似,并且都包含执行以下操作的方法:GetAll、Get、Create、Update 和 Delete

[Authorize]
[ApiController]
[Route("api/[controller]")]
public class VehicleTypeController : Controller
{
    private readonly IUnitOfWork _unitOfWork;
    private readonly ILogger<VehicleTypeController> _logger;
    private readonly IMapper _mapper;

    public VehicleTypeController(IUnitOfWork unitOfWork, ILogger<VehicleTypeController> logger, IMapper mapper)
    {
        _unitOfWork = unitOfWork;
        _logger = logger;
        _mapper = mapper;
    }

    [HttpGet]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    public async Task<IActionResult> Get()
    {
        var countries = await _unitOfWork.VehicleTypes.GetAll();

        var results = _mapper.Map<IList<VehicleTypeDTO>>(countries);

        return Ok(results);
    }

    [HttpGet("{id:int}", Name = "Get")]    
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    public async Task<IActionResult> Get(int id)
    {
        var VehicleType = await _unitOfWork.VehicleTypes.Get(i => i.Id == id);

        var results = _mapper.Map<VehicleTypeDTO>(VehicleType);

        return Ok(results);
    }

    [Authorize(Roles = "Administrator")]
    [HttpPost]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    public async Task<IActionResult> Create([FromBody] CreateVehicleTypeDTO VehicleTypeDto)
    {
        if (!ModelState.IsValid)
        {
            _logger.LogError($"Invalid POST attempt in {nameof(CreateVehicleType)}");
            return BadRequest(ModelState);
        }

        var VehicleType = _mapper.Map<VehicleType>(VehicleTypeDto);
        await _unitOfWork.VehicleTypes.Insert(VehicleType);
        await _unitOfWork.Save();

        return CreatedAtRoute("Get", new { id = VehicleType.Id }, VehicleType);
    }

    [Authorize(Roles = "Administrator")]
    [HttpPut("{id:int}")]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    public async Task<IActionResult> Update(int id, [FromBody] UpdateVehicleTypeDTO VehicleTypeDto)    
    {
        if (!ModelState.IsValid || id < 1)
        {
            _logger.LogError($"Invalid UPDATE attempt in {nameof(Update)}");
            return BadRequest(ModelState);
        }

        var VehicleType = await _unitOfWork.VehicleTypes.Get(a => a.Id == id);
        if (VehicleType == null)
        {
            _logger.LogError($"Submitted data is invalid.");
            return BadRequest(ModelState);
        }

        _mapper.Map(VehicleTypeDto, VehicleType);
        _unitOfWork.VehicleTypes.Update(VehicleType);
        await _unitOfWork.Save();

        return NoContent();
    }

    [Authorize(Roles = "Administrator")]
    [HttpDelete("{id:int}")]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    public async Task<IActionResult> Delete(int id)
    {
        if (id < 1)
        {
            _logger.LogError($"Invalid DELETE attempt in {nameof(Delete)}");
            return BadRequest();
        }

        var VehicleType = _unitOfWork.VehicleTypes.Get(i => i.Id == id);
        if (VehicleType == null)
        {
            _logger.LogError($"Invalid DELETE attempt in {nameof(Delete)}");
            return BadRequest("Submitted data is invalid.");
        }

        await _unitOfWork.VehicleTypes.Delete(id);
        await _unitOfWork.Save();

        return NoContent();
    }
}

用这些方法创建接口然后让这些类实现这个接口的最佳方法是什么?例如这样的事情......

public interface IGenericCRUD
{
    Task<IActionResult> Get();
    Task<IActionResult> Get(int id);
    Task<IActionResult> Create([FromBody] object myDto);
    Task<IActionResult> Update(int id, [FromBody] object myDto);
    Task<IActionResult> Delete(int id);
}

然后使用反射来动态调用基于泛型类型的适当方法?

因此,创建一个实现 IGenericCRUD 并包含核心 CRUD 代码的通用 CRUD 类,但使用通用 T。类似...

public class GenericCrud<T, TEntityDto> 

那么,在Get方法中,例如,是这样的吗?(它没有编译,所以我不确定我是否接近。)

    public async Task<IList<TEntityDto>> Get()
    {
        var getAllResults = await _unitOfWork.GetType(T).GetAll();

        var results = _mapper.Map<IList<TEntityDto>>(getAllResults);

        return results;
    }

我在正确的轨道上吗?有什么办法可以发布这个类的“通用”版本让我看到你的方法?

谢谢!

标签: c#asp.net-web-api.net-5

解决方案



推荐阅读