c# - API 中 POST 模型绑定(bind)问题

标签 c# asp.net-core

我无法理解 Asp.Net core 2 中的模型绑定(bind)过程。我有一个非常简单的 API,它有一个模型。它有一些基本的验证。每当用户发布不正确的模型时,我都会尝试返回 422 unprocessableentity 以及来自模型状态的错误消息。

我想了解的两个问题如下:

  • 如果我发布没有 ID 的请求,则会创建一个默认 ID 0 来绕过必需的属性。我假设这是为字段提供默认值的 C# 功能。有没有办法规避这个?

  • 另一个问题是,如果我在我的 post 操作中放置一个断点并发送一个错误的请求,它甚至不会进入该方法。它使用验证属性发回 400 错误请求。这是如何运作的?请求是否会在尝试绑定(bind)到无效属性(即名称长度 > 10)时立即停止?我需要它做的是发回具有相同错误消息的 422 不可处理实体,而不是 400。

如果基于验证属性的模型状态验证失败,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);
    }
}

最佳答案

对于您的第一个问题,如果您不想让该属性可以为空,您还可以放置一个范围属性 [Range(1, int.MaxValue)],但在这种情况下 0 将不是有效值。

对于你的第二个问题,如果你仍然想要 ApiControllerAttribute 的自动模型验证,但想要 422 响应代码而不是 400,你可以使用 InvalidModelStateResponseFactory 配置选项。

services.Configure<ApiBehaviorOptions>(options => 
{
  options.InvalidModelStateResponseFactory = ctx => 
     new UnprocessableEntityObjectResult(ctx.ModelState);
});

关于c# - API 中 POST 模型绑定(bind)问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52047921/

相关文章:

c# - 授予ASPNETDB.MDF SQL DB IIS_IUSRS权限

asp.net - .net 核心中的中间件不起作用,让我介入

c# - Newtonsoft.Json System.InvalidOperationException : Synchronous operations are disallowed

azure - 用于保护 Azure KeyVault 中的 Azure AD 应用程序客户端 ID 和 secret 的策略

c# - 异常处理程序中间件未捕获

c# - 如何在 IIS 上运行的 dotnet 核心应用程序中获得可见性/调试高内存使用率

c# - 我如何计算在体素游戏中应该首先加载哪些 block ?

c# - WebBrowser aspx 的命名空间

c# - CORS 不适用于路线

c# - 存储库模式和返回类型