Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 767
buddybubble Avatar asked Aug 07 '13 13:08

buddybubble


People also ask

How do I pass complex type in Web API?

Method 2: Using Newtonsoft JArraydll to your ASP.NET MVC project and WebAPI as well. Now, on Web API controller side, you will get your complex types within JArray as shown below. In this way, you can easily pass your complex types to your Web API. There are two solution, there may be another one as well.

What is FromUri and FromBody in Web API?

The [FromUri] attribute is prefixed to the parameter to specify that the value should be read from the URI of the request, and the [FromBody] attribute is used to specify that the value should be read from the body of the request.


2 Answers

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.

like image 148
Badri Avatar answered Sep 28 '22 04:09

Badri


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."]}}
like image 28
Tuukka Haapaniemi Avatar answered Sep 28 '22 05:09

Tuukka Haapaniemi