Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Web API model validation and default values

This is the spiritual successor to my previous question Web API attribute routing and validation - possible?, which I think was too general to answer. Most of those issues are solved, but the default value question remains.

Basically I have solved many pieces of the puzzle. I have this:

[HttpGet]
[Route("test/{id}"]
public IHttpActionResult RunTest([FromUri]TestRequest request)
{
    if (!ModelState.IsValid) return BadRequest(ModelState);
    return Ok();
}

My TestRequest class:

public class TestRequest
{
    public string id { get; set; }

    [DefaultValue("SomethingDefault")]
    public string something { get; set; }
}

The problem is that if no parameter is in the query string for something, the model is "valid" and yet something is null.

If I specify a blank value for something (i.e. GET test/123?something=), then the default value comes into play, and the model is valid again.

Why is this? How can I get a default value into my model here? As a bonus, why is it when a parameter is not specified, the default value is not used, but when a blank string is explicitly specific, the default value is used?

(I've been trawling through the ASP.NET stack source code and am knee-deep in model binders and binding contexts. But my best guess can't be right - it looks like the DefaultValueAttribute is used only if the parameter value is null. But that's not the case here)

like image 561
Kieren Johnstone Avatar asked May 27 '15 12:05

Kieren Johnstone


1 Answers

You need to initialize the default value in the constructor for your Model:

public class TestRequest
{
    public TestRequest()
    {
        this.something = "SomethingDefault";
    }

    public string id { get; set; }

    [DefaultValue("SomethingDefault")]
    public string something { get; set; }
}

Update:
With C# 6, you don't need to initialize it in the constructor anymore. You can assign the default value to the property directly:

public class TestRequest
{
    public string id { get; set; }

    [DefaultValue("SomethingDefault")]
    public string something { get; set; } = "SomethingDefault";
}

As documentation of the DefaultValueAttribute states:

Note

A DefaultValueAttribute will not cause a member to be automatically initialized with the attribute's value. You must set the initial value in your code.

In the case where you're providing no value for your something property, the property is initialized and the ModelBinder doesn't have a value to assign to it and thus the property defaults to its default value.

like image 193
Konstantin Dinev Avatar answered Oct 05 '22 11:10

Konstantin Dinev