JSON to Model property binding using JsonProperty

2020-07-18 08:56发布

问题:

I'm bound by agreements between my party and the client to use json parameters containing dashes. Since it's not possible to use that in property names in C#, I need to map to the desired property.

What I do now:

The below code is simplified for convenience.

Model

public class MyRequest
{
    [JsonProperty("request-number")]
    public string RequestNumber { get; set; }

    [JsonProperty("name")]
    public string Name { get; set; }
}

Controller

[HttpGet]
[Route("api/load-stuff")]
public Stuff LoadStuff([FromUri]MyRequest request)
{
    return BackEnd.LoadStuff(request);
}

Call to the API from client

The above controller is targeted using this uri:

http://localhost:12345/api/load-stuff?request-number=X123&name=requestName

My question

If I put a breakpoint at the BackEnd.LoadStuff line I can see the call arrives, but the request isn't mapped correctly.

Name contains what I expect: requestName, but RequestNumber is null, so the mapping didn't work.

What's going wrong?

回答1:

ASP.NET's default model binder doesn't take the JsonPropertyAttribute into account when attempting to bind request parameters to a model (it can't, since it doesn't know about JsonPropertyAttribute and the rest of NewtonSoft.Json). Given your scenario (property names that aren't legal identifiers in C#), the only way to achieve what you want is via a custom model binder that does read JsonPropertyAttribute.

If you did have property names that were legal identifiers (for example request_number) then you could create a request model with those named properties, then map it to a separate model with the correctly-named properties, e.g.:

public class MyController : ApiController
{
    [HttpGet]
    [Route("api/load-stuff")]
    public Stuff LoadStuff([FromUri]MyRequest request)
    {
        return BackEnd.LoadStuff(request.ToMyPrettyRequest());
    }
}

public class MyRequest
{
    public string request_number { get; set; }

    public string name { get; set; }

    MyPrettyRequest ToMyPrettyRequest()
    {
        return new MyPrettyRequest
        {
            RequestNumber = request_number,
            Name = name,
        };
    }
}

public class MyPrettyRequest
{
    public string RequestNumber { get; set; }

    public string Name { get; set; }
}