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)
Specifying the default in the constructor works for when no parameter is specified at all, but when a blank string is specified,
null
is put into the field instead.As such, adding
[DefaultValue("")]
actually worked the best - when a blank string was specified, a blank string was passed in. Then the constructor can specify default values for when the parameter is missing.To get around this, I've created
PreserveBlankStringAttribute
, derives fromDefaultValueAttribute
which is equivalent to[DefaultValue("")]
.I would very much welcome a better answer than this, please.
You need to initialize the default value in the constructor for your Model:
As documentation of the DefaultValueAttribute states:
In the case where you're providing no value for your
something
property, the property is initialized and theModelBinder
doesn't have a value to assign to it and thus the property defaults to its default value.