tschmit
tschmit

Reputation: 7800

model binding behavior varie between Controller and ControllerBase with [ApiController]

I use asp dotnet core V6 (that is the preview version).

I have two identical methods, one in an MVC controller, the other in an Api Controller. The signature of the methods are:

for MVC

 public async Task<ActionResult> Variable(Models.DTParameters dtp)

for api

[HttpGet]
[Consumes("application/x-www-form-urlencoded")]
[Route("api/Select/Variable")]
public async Task<ActionResult> Variable([FromQuery] Models.DTParameters dtp)

the methods are called by jquery $.ajax

for MVC:

{
     method: 'POST',
     url: '/Select/Variable'
}

for api:

{
     method: 'GET',
     url: '/api/Select/Variable'
}
MVC api
All is fine Only the simple property (draw, start, length) are binded.the others (search...) are null.
If I try with method='POST' and [FromBody], I end with an error: "Not supported media type"

Any idea on how to get ApiController correctly bind DTParameters ?

----- EDIT 1

it works if I remove the [ApiController] attibute from my api controller:

//[ApiController]
public class SelectController : ControllerBase

for my mvc controller the declaration is:

public class SelectController : Controller

----- EDIT 2

with [ApiController] and the following declaration:

[HttpPost]
[Consumes("application/json")]
[Route("api/Select/Variable")]
public async Task<ActionResult> Variable(Models.DTParameters dtp)

I now get an error 400:

{"type":"https://tools.ietf.org/html/rfc7231#section-6.5.1","title":"One or more validation errors occurred.","status":400,"traceId":"00-9753afa4b5fc5ed24f3605c3edd51d8e-25872b0ff804e179-00","errors":{"$.order[0].dir":["The JSON value could not be converted to adaptator.wgui.Models.DTOrderDir. Path: $.order[0].dir | LineNumber: 0 | BytePositionInLine: 151."]}}

where position value 151 correponds to the " after the last c in

"order":[{"column":0,"dir":"asc"}]

It seems that the binder can't handles the DTOrderDir enum.

----- ANNEXE

where DTParmeters is:

public class DTParameters {
    public int Draw { get; set; }
    public DTColumn[] Columns { get; set; }
    public DTOrder[] Order { get; set; }
    public int Start { get; set; }
    public int Length { get; set; }
    public DTSearch Search { get; set; }
    public DTKeyValue[] MoreForSearch { get; set; }
}
public class DTKeyValue {
    public string Key { get; set; }
    public string Value { get; set; }
}
public class DTColumn {
    public string Data { get; set; }
    public string Name { get; set; }
    public bool Searchable { get; set; }
    public bool Orderable { get; set; }
    public DTSearch Search { get; set; }
}
public class DTOrder {
    public int Column { get; set; }
    public DTOrderDir Dir { get; set; }
}
public enum DTOrderDir {
    asc,
    desc
}
public class DTSearch {
    public string Value { get; set; }
    public bool Regex { get; set; }
}

Upvotes: 0

Views: 228

Answers (1)

Serge
Serge

Reputation: 43959

just fix action attributes. Remove ALL attributes except Route

mvc


[Route("~/Select/Variable")]
public async Task<ActionResult> Variable(Models.DTParameters dtp)

api


[Route("~/api/Select/Variable")]
public async Task<ActionResult> Variable( Models.DTParameters dtp)

and fix ajax

mvc

{
     method: 'POST',
     url: '/Select/Variable'
}

api

{
     method: 'POST',
     url: '/Select/Variable'
}

if you don't have [ApiController] attribute use this for API

{
     method: 'POST',
     url: '/Api/Select/Variable'
}

Upvotes: 1

Related Questions