buddybubble
buddybubble

Reputation: 1319

ASP.net WebApi Parameter Binding to complex type from URI

I want to create a REST webservice using ASP.net WebApi on .net 4.5

Urls should be of a format like this:

/values?Age=55&Height=176&Race=1&Weight=80&Gender=male&id=800001

The associated controller looks like this:

[HttpGet]
public string Get(int id, [FromUri]Demographics demographics)
{ // etc.}

Where Demographics is a custom object that is basically just a DTO with certain properties. However, it contains one property that has the type of a custom enum:

enum Gender
{
 Female = 0,
 Male
}

The default mapping works just fine if the URL is of the above format. However, of course I also need to check whether the parameters provided by the url are correct.

ASP.net WebApi (afaik) per default tries to map each parameter based on the assumed type (or if it can be converted to that type). If it can't find a matching value in the URI it appears to assume it is just 0.

Now this takes me to a very unfortunate situation where 0 is by definition still a valid value for Gender Demographics.Gender (0 ~ Gender.Female).

The simplest solution would be to change the enum so that 0 would be a "indeterminate" state that I could check for. However, I can not change the enum. I could create my own overload for the Demographics object but would rather not do this, because I think there must be a nicer way.

Can I explicitely bind the gender parameter to a parameter in the URI and throw an exception if it was not submitted?

I read about type converters but I would have to work on the URI string and think I would have to implement a lot functionality that WebApi apparently already has.

Please keep in mind that I have to work on the URI and can not use the Request Body.

Upvotes: 5

Views: 3160

Answers (2)

Tuukka Haapaniemi
Tuukka Haapaniemi

Reputation: 1264

WebAPI contains a validation framework through data annotations. This allows you to mark the Gender-property in the Demographics object as [Required]:

public class Demographics
{
    [Required]
    public Gender Gender { get; set; }
}

Then, mark the controller or the controller method with the [ValidateModel] attribute to force validation (read about other ways to force this, e.g. globally: model validation):

[HttpGet]
[ValidateModel]
public string Get(int id, [FromUri]Demographics demographics)
{ // etc.}

After this, if you miss to provide the parameter, you'll get automatic validation and an error 400 Bad Request with a message:

{"Message":"The request is invalid.","ModelState":{"Gender":["The Gender field is required."]}}

Invalid values are handled correctly by default, even without the required attribute, so an incorrect value of Foo provided to the gender is responded also with a 400 Bad Request message:

{"Message":"The request is invalid.","ModelState":{"Gender":["The value 'Foo' is not valid for Gender."]}}

Upvotes: 1

How about making the enum nullable like this?

public class Demographics
{
    public Gender? Gender { get; set; }
}

Inside the action method, you can just check if demographics.Gender is null or not.

Upvotes: 4

Related Questions