[英]C# OData Web API POST endpoint with IEnumerable in parameters returns error 400 the input was not valid
我在這里有一個怪異的行為。 我在這里有一個 controller (我在這里欺騙和混淆了很多東西......它仍然相關)
[Route("api/[controller]")]
[ApiController]
public class MyComplexTypeController : ControllerBase
{
//context...
public MyComplexTypeController()
{
//context..
}
[HttpPost]
// For simplicity, I have renamed the endpoint..
// In reality I just have ONE Post endpoint here
public ActionResult MyCallThatWorks(MyComplexObj param_origData)
{
// The param_origData is GREAT and working!
return Ok();
}
[HttpPost]
// For simplicity, I have renamed the endpoint.
// In reality I just have ONE Post endpoint here
public ActionResult MyCallThatDontWorks(IEnumerable<MyComplexObj> param_origData)
{
// I get a 400 "The input was not valid." in PostMan!
return Ok();
}
在這里你有startup.cs
:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddAutoMapper(typeof(Startup2));
services.AddCors();
services.AddRazorPages();
services.AddOData();
services.AddControllers()
//https://docs.microsoft.com/en-us/aspnet/core/web-api/advanced/formatting?view=aspnetcore-5.0
.AddJsonOptions(options =>
options.JsonSerializerOptions.PropertyNamingPolicy = null);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseCors(x => x.AllowAnyMethod().AllowCredentials().AllowAnyHeader().SetIsOriginAllowed(x => true));
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.Select().Filter().OrderBy().Expand().Count().MaxTop(null);
endpoints.MapODataRoute("odata", "api", MyGetEdmModel());
});
}
private static IEdmModel MyGetEdmModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<MyComplexObj>("MyComplexType");
return builder.GetEdmModel();
}
}
事實上,我有 3 個復雜類型和 3 個端點。 我的兩個端點與 OData 一起正常工作。
我的第三種類型,這里解釋的那種,也適用(GET,POST,DELETE)!
但是:我的端點的POST
僅在我傳遞我的復雜 class 的一個實例時才有效。 如果我通過IEnumerable
(並正確傳遞 Postman [ { "bla":12" }, { "bla":24 }]
中的數據,它將不起作用。
我嘗試了很多東西。 僅舉幾個:
刪除 controller 屬性中的[ApiController]
(抱歉,我找不到鏈接..) - 沒用:我在我的參數中獲得了NULL
值(但仍在輸入方法)
嘗試傳遞 DTO(同樣的問題 - 錯誤 400)
試圖在參數中創建一個動態/對象/字符串的傳遞(丑陋並且必須努力將其轉換回來)
嘗試過 OData Actions 和 Odata CollectionParameter function (沒能幸存下來) -編輯:這就是解決方案!
試圖通過它[FromBody]
,並且沒有[FromBody]
(所以 xxx-form-encoded) - 正在輸入方法,但得到了NULL
!
在 Postman 中,我嘗試使用
{"":[{"Mycollection":"Of"},{"Complex":"Objet"}]}
也試過
=[{"Mycollection":"Of"},{"Complex":"Objet"}]
(如 MS docs..ahah 中某處所述)
我在 Google 中做了標准的“為什么 Odata 如此糟糕”,打算嘗試 GraphQL,但我確實抗拒了......
我終於做了一個聰明的程序員必須做的事情:我從基地重新開始。
長話短說:OData 不能容忍我的參數簽名與初始路由不匹配。
所以我不得不在我的Startup.cs
中刪除這一行:
private static IEdmModel MyGetEdmModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<MyComplexObj>("MyComplexType"); <--THIS ONE
builder.EntitySet<OtherComplexType>("OtherComplexType");
builder.EntitySet<OtherComplexType2>("OtherComplexType2");
return builder.GetEdmModel();
}
並且通過IEnumerable
效果很好!
問題:為什么?
現在,我無法對該特定實體進行完整的 OData 獲取(無法找到非 OData 路由的服務容器)。 這很正常,我剛剛刪除了它!
我剛剛找到了這個(在寫完我的帖子之后):
WebApi OData 4,用於在 controller 中批量插入的第二個 POST 端點
似乎是答案,並保持一切“OData 批准”!
如此大的圖景,為了能夠發布與注冊的 OData 類型不同的 TYPE,您必須創建一個名為 Action 的新端點(方法)。 此操作可以采用您定義的任何類型(在 startup.cs 中):
private static IEdmModel MyGetEdmModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<xxx>("xx");
builder.EntitySet<yyyy>("yyy");
builder.EntitySet<MyComplexType>("MyComplexType");
// added this line here:
builder.EntityType<MyComplexType>().Collection
.Action("BulkAdd")
.CollectionParameter<MyComplexType>("MyXREF");
return builder.GetEdmModel();
}
然后,在controller的方法中:
[HttpPost]
public async Task<ActionResult> BulkAdd(ODataActionParameters parameters)
{
if (!ModelState.IsValid)
{
return BadRequest();
}
List<MycomplexType> bookings = ((IEnumerable<MycomplexType>)parameters["MyXREF"]).ToList();
瞧!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.