我无法理解Asp.Net core 2中的模型绑定过程。我有一个非常简单的具有模型的API。它具有一些基本的验证。每当用户发布不正确的模型时,我都会尝试返回422无法处理的实体以及来自modelstate的错误消息。
我要理解的两个问题如下:
如果我发布不带ID的请求,则会绕过必需的属性创建默认ID 0。我假设这是C#功能,用于为字段提供默认值。有办法避免这种情况吗?
另一个问题是,如果我在发布操作中放置一个断点并发送错误的请求,它甚至不会进入该方法。它使用验证属性发送回一个400错误的请求。这是如何运作的?请求尝试建模时是否会立即绑定到无效属性(即名称长度> 10)?我需要做的是发送回具有相同错误消息而不是400的422无法处理的实体。
如果基于验证属性的模型状态验证失败,ASP.NET甚至不会进入该方法吗?解决此问题以返回422错误代码的更好方法是什么?
下面是我各种类的代码(创建项目时使用了API模板):
Startup.cs -我在这里添加的唯一内容是内存中上下文的单例实例
public void ConfigureServices(IServiceCollection services)
{
//services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddMvc();
services.AddSingleton<IItemRepository, ItemRepository>();
}
IItemRepository.cs -我的DI界面
public interface IItemRepository
{
List<ItemModel> Items { get; set; }
void AddValue(ItemModel itemModel);
}
ItemRepository.cs -具体实施方式
public class ItemRepository : IItemRepository
{
public List<ItemModel> Items { get; set; } = new List<ItemModel>();
public ItemRepository()
{
Items.AddRange(
new List<ItemModel> {
new ItemModel {Id = 1, Name = "Test1" },
new ItemModel {Id = 2, Name = "Test2" }
}
);
}
public void AddValue(ItemModel itemModel)
{
Items.Add(itemModel);
}
}
ItemModel.cs -用于用户输入的我的模型类
public class ItemModel
{
[Required]
public int Id { get; set; }
[MaxLength(10)]
public string Name { get; set; }
}
ValuesController.cs
[Route("api/[controller]")]
[ApiController]
public class ValuesController : Controller
{
private IItemRepository _context;
public ValuesController(IItemRepository context)
{
_context = context;
}
// GET api/values
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return Ok(_context.Items);
}
// GET api/values/5
[HttpGet("{id}", Name = "GetSingle")]
public ActionResult<string> Get(int id)
{
return Ok(_context.Items.Where(x => x.Id == id));
}
// Problem here - placing a breakpoint in below method does not do anytthing as it will return a 400 bad request instead of 422
[HttpPost]
public ActionResult Post([FromBody] ItemModel itemModel)
{
if (!ModelState.IsValid)
{
return new UnprocessableEntityObjectResult(ModelState);
}
ItemModel addNew = new ItemModel { Id = itemModel.Id, Name = itemModel.Name };
_context.AddValue(addNew);
return Ok(addNew);
}
}
答案 0 :(得分:1)
如果我发布的请求中没有ID,则默认ID为0 避开必需的属性。我假设这是C# 向字段提供默认值的功能。有办法吗 规避这个?
@StephenMuecke回答here时,您需要将模型更改为
state
另一个问题是,如果我在发布操作中放置一个断点 并发送错误的请求,它甚至不会进入该方法。它发送 通过使用验证属性返回400错误的请求。如何 这项工作?尝试建立模型绑定到该请求后,该请求是否会暂停 属性无效(即名称长度> 10)?我需要做的是 发回具有相同错误消息的422无法处理的实体 而不是400。
这是因为您将public class ItemModel
{
[Required]
public int? Id { get; set; }
[MaxLength(10)]
public string Name { get; set; }
}
应用于控制器。 From the documentation:
验证错误会自动触发HTTP 400响应。以下代码在您的操作中变得不必要:
ApiControllerAttribute
您可以删除属性,或者如同一链接所述,将其添加到启动配置中:
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
答案 1 :(得分:1)
可以通过使该属性可为空来解决您的第一个问题。正如Stepen Muecke所说。
也来看看here,也许BindRequired属性可以提供帮助。本文还介绍了如何调整行为。
对于第二个问题,这是Asp.Net Core 2.1的new(中断)行为。新的是automatic 400 response。这就解释了为什么没有击中断点的原因。您可以按以下步骤取消此操作:
Tools::getValue('Name_Kombinezony')
答案 2 :(得分:1)
对于第一个问题,如果您不想使该属性可为空,则还可以放置range属性[Range(1,int.MaxValue)],但是在这种情况下,0将不是有效值。
对于第二个问题,如果您仍然希望通过ApiControllerAttribute进行自动模型验证,但想要422响应代码而不是400,则可以使用InvalidModelStateResponseFactory配置选项。
services.Configure<ApiBehaviorOptions>(options =>
{
options.InvalidModelStateResponseFactory = ctx =>
new UnprocessableEntityObjectResult(ctx.ModelState);
});