[英]Issue with Model Binding on POST in API
我無法理解Asp.Net核心2中的模型綁定過程。我有一個非常簡單的API,它有一個模型。 它有一些基本的驗證。 每當用戶發布不正確的模型時,我都會嘗試從模型狀態返回422不可處理的實體以及錯誤消息。
我試圖理解的兩個問題如下:
如果我發布沒有ID的請求,則會創建默認ID 0以繞過所需屬性。 我假設這是C#功能,為字段提供默認值。 有沒有辦法規避這個?
另一個問題是,如果我在post 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>();
}
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);
}
}
如果我發布沒有ID的請求,則會創建默認ID 0以繞過所需屬性。 我假設這是C#功能,為字段提供默認值。 有沒有辦法規避這個?
正如@StephenMuecke 在這里回答的那樣,您需要將模型更改為
public class ItemModel
{
[Required]
public int? Id { get; set; }
[MaxLength(10)]
public string Name { get; set; }
}
另一個問題是,如果我在post post中放置一個斷點並發送一個錯誤的請求,它甚至不會進入該方法。 它使用驗證屬性發回400錯誤請求。 這是如何運作的? 一旦嘗試將綁定建模為無效屬性(即名稱長度> 10),請求是否會暫停? 我需要它做的是發送一個422不可處理的實體與相同的錯誤消息而不是400。
這是因為您將ApiControllerAttribute
應用於Controller。 從文檔 :
驗證錯誤會自動觸發HTTP 400響應。 您的操作中不再需要以下代碼:
if (!ModelState.IsValid) { return BadRequest(ModelState); }
您可以刪除該屬性,或者,如同相同的鏈接所解釋的,將其添加到啟動配置:
services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressModelStateInvalidFilter = true;
})
對於第一個問題,如果您不想使屬性可為空,您還可以放置范圍屬性[Range(1,int.MaxValue)],但在這種情況下0將不是有效值。
對於第二個問題,如果您仍希望從ApiControllerAttribute進行自動模型驗證但需要422響應代碼而不是400,則可以使用InvalidModelStateResponseFactory配置選項。
services.Configure<ApiBehaviorOptions>(options =>
{
options.InvalidModelStateResponseFactory = ctx =>
new UnprocessableEntityObjectResult(ctx.ModelState);
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.