2

Hello,

I have api GET-method /rating (ASP.Net WebApi 2.1), which accepts objects of type ChartPageRequest:

// comments're removed for readability
public sealed class ChartPageRequest
{
    public DateTime? From { get; set; }

    public DateTime? To { get; set; }

    public string Cursor { get; set; }

    [Range(-100, 100)]
    public int Take { get; set; } = 10;
}

/rating method has following signature:

[HttpGet]
[Route("rating")]
[ResponseType(typeof(ChartPage))]
[ValidateModelState]
public async Task<IHttpActionResult> GetTranslationRatingChartAsync([ModelBinder] ChartPageRequest model)
{
    // body here
}

And ValidateModelState attribute is just a custom attribute which returns custom response when ModelState isn't valid. It doesn't check anything by itself except HttpActionContext.ModelState.IsValid property.

This api method works fine except one case - when client explicitly passes null value to DateTime? properties of ChartPageRequest, e.g.:

/rating?from=2016-07-08 12:01:55.604&to=null

In this case ValidateModelState attribute registers invalid ModelState with following message: The value 'null' is not valid for To.

I've found this kind of problem quite popular, but haven't found any good workarounds without creating custom model binder. So here's the questions:

  1. Is there another approach without custom model binder?

  2. In case there isn't, how can I take only "accepting null" job and leave DateTime parsing to default binder in my custom binder?

  3. Do I need to accept those nulls at all? All clients are developing by my colleagues so I can force them to not send it. Is it good practice after all?

Thanks!

pkuderov
  • 3,501
  • 2
  • 28
  • 46
  • 3
    Do not include the value at all in the query string. If you have external clients that are not controlled by you then you should inform them or update the documentation so that they know that null values should be omitted. This goes for everything that you pass, not just this date time. If you try it with an int? or a string you will also get unexpected results (error with the int, probably a literal "null" string with the string assinment). – Igor Sep 19 '16 at 14:07
  • @Igor, I'll update my question and will ask if it's good practice. Thank you – pkuderov Sep 19 '16 at 14:09
  • Check [this answer](http://stackoverflow.com/a/31255151/1260204) if you want to include it in the query string even if there is no value: . `/rating?from=2016-07-08 12:01:55.604&to=%00`. I recommend just omit it though if it is not necessary. As to what best practice is that might be a matter of opinion. – Igor Sep 19 '16 at 14:17
  • Oh, thanks again, mate! I always thought this problem doesn't exist for the others primitive types and I've just realized it's not true :) Ok, so this problem is about passing nulls at all. It seems I need to talk with api clients ;) – pkuderov Sep 19 '16 at 14:23

1 Answers1

0

I didn't validate this method, but I guess you can try parse it yourself, though I think it's not a convenient way, first use a string to get the To:

public string To { get; set; }

And give another property DateTimeTo and parse To yourself:

public DateTime? DateTimeTo { get; set; }

public void ParseTo()
{
    if(To.ToLower() == "null")
        DateTimeTo = null;
    else
        DateTimeTo = Convert.ToDateTime(To); 
}

And DateTimeTo is the parsed result property.

I recently ran into some Asp.Net WebApi parsing body issue, the parsing doesn't work very well in some condition.

yu yang Jian
  • 6,680
  • 7
  • 55
  • 80