Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/email/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# API中POST上的模型绑定问题_C#_Asp.net Core - Fatal编程技术网

C# API中POST上的模型绑定问题

C# API中POST上的模型绑定问题,c#,asp.net-core,C#,Asp.net Core,我很难理解Asp.NETCore2中的模型绑定过程。我有一个非常简单的API,它有一个模型。它有一些基本的验证。每当用户发布错误的模型时,我都会尝试返回422 unprocessableentity以及来自modelstate的错误消息 我想了解的两个问题如下: services.Configure<ApiBehaviorOptions>(options => { options.SuppressModelStateInvalidFilter = true; });

我很难理解Asp.NETCore2中的模型绑定过程。我有一个非常简单的API,它有一个模型。它有一些基本的验证。每当用户发布错误的模型时,我都会尝试返回422 unprocessableentity以及来自modelstate的错误消息

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

services.Configure<ApiBehaviorOptions>(options =>
{
    options.SuppressModelStateInvalidFilter = true;
});
  • 如果我发布了一个没有ID的请求,则会绕过必需的属性创建一个默认ID 0。我假设这是为字段提供默认值的C#功能。有没有办法避免这种情况

  • 另一个问题是,如果我在post操作中放置一个断点并发送一个错误的请求,它甚至不会进入该方法。它使用验证属性发回400个错误请求。这是怎么回事?请求是否在尝试将模型绑定到无效属性(即名称长度>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>();
}
值控制器.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);
    }
}
[路由(“api/[控制器]”)]
[ApiController]
公共类值控制器:控制器
{
私有IItemRepository_上下文;
公共价值控制器(IItemRepository上下文)
{
_上下文=上下文;
}
//获取api/值
[HttpGet]
公共行动结果获取()
{
返回Ok(_context.Items);
}
//获取api/values/5
[HttpGet(“{id}”,Name=“GetSingle”)]
公共操作结果获取(int-id)
{
返回Ok(_context.Items.Where(x=>x.Id==Id));
}
//这里的问题-在下面的方法中放置断点不会执行任何操作,因为它将返回一个400错误请求,而不是422错误请求
[HttpPost]
公共操作结果发布([FromBody]ItemModel ItemModel)
{
如果(!ModelState.IsValid)
{
返回新的不可处理EntityObjectResult(ModelState);
}
ItemModel addNew=newitemmodel{Id=ItemModel.Id,Name=ItemModel.Name};
_AddValue(addNew);
返回Ok(新增);
}
}
如果我发布一个没有ID的请求,将创建一个默认ID 0 绕过必需的属性。我假设这是C# 为字段提供默认值的功能。有办法吗 为了避免这种情况

如前所述,您需要将模型更改为

public class ItemModel
{
    [Required]
    public int? Id { get; set; }

    [MaxLength(10)]
    public string Name { get; set; }
}
另一个问题是,如果在post操作中放置断点 并且发送一个错误的请求,它甚至没有进入方法。它发出 使用验证属性返回400错误请求。怎么做 这工作?请求是否在尝试模型绑定时立即停止 无效属性(即名称长度>10)?我需要它做的是 发回带有相同错误消息的422不可处理实体 而不是400

这是因为您将
ApiControllerAttribute
应用于控制器:

验证错误会自动触发HTTP 400响应。以下代码在您的操作中变得不必要:

if (!ModelState.IsValid)
{
    return BadRequest(ModelState);
}
您可以删除该属性,或者按照同一链接的说明,将其添加到启动配置中:

services.Configure<ApiBehaviorOptions>(options =>
{
    options.SuppressModelStateInvalidFilter = true;
})
services.Configure(选项=>
{
options.SuppressModelStateInvalidFilter=true;
})

您的第一个问题可以通过使属性为空来解决。正如Stepen Muecke所评论的那样

另外请看一看,BindRequired属性可能会有所帮助。本文还介绍了如何调整行为

对于第二个问题,这是Asp.NETCore2.1的(破坏性)行为。新的是新的。这就解释了为什么没有命中断点。您可以按如下方式抑制此操作:

services.Configure<ApiBehaviorOptions>(options =>
{
    options.SuppressModelStateInvalidFilter = true;
});
services.Configure(选项=>
{
options.SuppressModelStateInvalidFilter=true;
});

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

对于第二个问题,如果仍然希望从ApiControllerAttribute进行自动模型验证,但希望使用422响应代码而不是400,则可以使用InvalidModelStateResponseFactory配置选项

services.Configure<ApiBehaviorOptions>(options => 
{
  options.InvalidModelStateResponseFactory = ctx => 
     new UnprocessableEntityObjectResult(ctx.ModelState);
});
services.Configure(选项=>
{
options.InvalidModelStateResponseFactory=ctx=>
新的不可处理EntityObjectResult(ctx.ModelState);
});

发送错误请求
能否向我们展示错误请求的示例?请将您的
Id
属性(视图模型)设置为空且
[必需]
-谢谢您和@StephenMuecke。这回答了我的问题。我没有意识到,使用新的apicontroller属性,它会自动触发错误的请求。在我的ID上使用可空类型修复了这个问题。这更全面地回答了这个问题。
services.Configure<ApiBehaviorOptions>(options =>
{
    options.SuppressModelStateInvalidFilter = true;
});
services.Configure<ApiBehaviorOptions>(options => 
{
  options.InvalidModelStateResponseFactory = ctx => 
     new UnprocessableEntityObjectResult(ctx.ModelState);
});