问题描述
我正在创建一个dotnet core 3.1 API以在现有系统中工作。 [dbo]。[MyTable]表具有两个具有UNIQUE约束的字段:[ID]和[HumanReadableID]。 [ID]是一个GUID,将在发布新资源时由API确定。 [HumanReadableID]必须由用户确定,因此API必须在执行插入操作之前首先通过查询数据库来确保其唯一性。
我尝试使用自定义属性进行此验证,并且还在控制器方法接受的DTO上实现IValidatableObject
,但是我无法将我的存储库注入到这两个对象中的任何一个中。 / p>
目前,控制器尝试使用存储库尝试插入,如果[HumanReadableID]不唯一,则会引发自定义异常,然后抛出。 。 。好吧,这是代码
[Route("[controller]")]
[ApiController]
public class MyThingsController : ControllerBase
{
/// Other methods
[HttpPost(Name = "CreateMyThing")]
public async Task<IActionResult> CreateMyThing(MyThingCreateDto myThingToCreate)
{
try
{
MyThingEntity entityToCreate = _mapper.Map<MyThingEntity>(myThingToCreate);
MyThingEntity entityToReturn = await _myRepository.InsertThing(entityToCreate);
MyThingDto myThingToReturn = _mapper.Map<MyThingDto>(entityToReturn);
return CreatedAtRoute(
"GetMyThing",new {id = myThingToReturn.Id},myThingToReturn);
}
catch (DuplicateHumanReadableIdException e)
{
ModelState.AddModelError("HumanReadableID",$"HumanReadableID {entityToCreate.HumanReadableId} is already used by site {e.IdOfThingWithHumanReadableId}");
return Conflict(ModelState);
}
}
}
这部分起作用,但是由此产生的错误的Content-Type为application/json
而不是application/problem+json
。此外,这就像感觉控制器在这里负有太多责任。
缺少使用IValidatableObject或DataAnnotations进行验证的实现方式是什么?如果失败了,我必须在控制器的ModelState中进一步进行哪些操作,以使其发出符合标准的谴责?
解决方法
有关如何实现IValidatableObject的信息,您可以按照以下步骤操作:
git credential.helper
型号:
public class ValidatableModel : IValidatableObject
{
public int Id { get; set; }
public int HumanReadableID { get; set; }
public string Name { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var service = validationContext.GetService<ICheckHumanReadableID>();
var flag = service.IfExsitHumanId(((ValidatableModel)validationContext.ObjectInstance).HumanReadableID);
if(flag)
{
yield return new ValidationResult(
$"The HumanReadableID is not unique.",new[] { nameof(HumanReadableID) });
}
}
}
服务:
public class Human
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
测试方法:
public interface ICheckHumanReadableID
{
bool IfExsitHumanId(int id);
}
public class CheckHumanReadableID : ICheckHumanReadableID
{
private readonly YourDbContext _context;
public CheckHumanReadableID(YourDbContext context)
{
_context = context;
}
public bool IfExsitHumanId(int id)
{
var list = _context.Human.Select(a => a.Id).ToList();
var flag = list.Contains(id);
return flag;
}
}
DbContext:
[HttpPost]
public async Task<ActionResult<ValidatableModel>> PostValidatableModel([FromForm]ValidatableModel validatableModel)
{
if(ModelState.IsValid)
{
_context.ValidatableModel.Add(validatableModel);
await _context.SaveChangesAsync();
return CreatedAtAction("GetValidatableModel",new { id = validatableModel.Id },validatableModel);
}
return BadRequest(ModelState);
}
Startup.cs:
public class YourDbContext: DbContext
{
public YourDbContext(DbContextOptions<YourDbContext> options)
: base(options)
{
}
public DbSet<ValidatableModel> ValidatableModel { get; set; }
public DbSet<Human> Human { get; set; }
}