26

I created an EF4.1 code-first model (may or may not be important), and I'm trying to get default values for my Create scaffold template. My model looks like:

class Person {
    [DefaultValue (18)]
    public int Age { get; set; }
}

And then my Create view looks like:

<div class="editor-label">
    @Html.LabelFor(model => model.Age)
</div>
<div class="editor-field">
    @Html.EditorFor(model => model.Age)
    @Html.ValidationMessageFor(model => model.Age)
</div>

I would expect at runtime, that the EditorFor would pre-populate the textbox with "18", but it does no such thing. Am I misunderstanding what the DefaultValue attribute is for, or is there something else I should be doing?

Note: I don't want to use the new { Value = "18" } override on the EditorFor method, it seems to break DRY.

Bryan Boettcher
  • 4,412
  • 1
  • 28
  • 49

5 Answers5

34

I don't know if this will satisfy your DRY needs, but it's a start I think.

I would rework the model a bit like this:

public class Person {
    private const int DEFAULT_AGE = 18;
    private int _age = DEFAULT_AGE;
    [DefaultValue(DEFAULT_AGE)]
    public int Age {
        get { return _age; }
        set { _age = value; }
    }
}

Keep the view as is, but in the create action do this:

public ActionResult Create() {
    return View(new Person());
}

That way, the input textbox will be created with the default Age value, and there will be only one place where that default will be specified.

Kenji Kina
  • 2,402
  • 3
  • 22
  • 39
  • I should add that I did already try setting the Age property in the constructor, which didn't seem to work either. The View is strongly-typed to Person though. However, what I was missing, was passing a new Person into the view. That did what I wanted it to, and your solution is DRY enough :) (I'm omitting DefaultValue entirely, and just using the constructors) – Bryan Boettcher Jul 21 '11 at 18:15
  • How do you access the DefaultValue attribute? I can't find it. – Hanna Apr 18 '12 at 16:18
  • @Johannes perhaps you are missing the `using System.ComponentModel` - http://msdn.microsoft.com/en-us/library/system.componentmodel.defaultvalueattribute.aspx – Kenji Kina Apr 18 '12 at 19:53
  • DefaultValue only works on the model binding for the view but it doesn't for the constructor when you pass it again to the controller. If no age is passed, it will be null instead of the default value. You must have a constructor to work both sides. – Bart Calixto Jun 26 '13 at 14:47
  • 2
    Note that code first migrations does not pickup these default values. You'd need to manually add them into the migration script, in the call that defines the type you can pass a defaultValue argument. See http://stackoverflow.com/a/13953246/70182 – Bart Verkoeijen Oct 27 '13 at 14:45
7
class Person {
    public Person() {
        Age = 18;    
    }
    public int Age { get; set; }
}

In this scenario, every time you do a new Person age will be initialized with 18 as age, even when the new object is created by the Model Binder.

Bart Calixto
  • 19,210
  • 11
  • 78
  • 114
1

Model

class Person {
    public Person() {
        Age = 18;    
    }
    public int Age { get; set; }
}

Controller

public ActionResult Create() {
    return View(new Person());
}

It works fine.

Dan
  • 681
  • 2
  • 11
  • 23
1

Assuming that your view has a definition such as:-

@model Person

and your controllers HTML GET returns an empty View

return View();

Then simply add a class that can be rendered that contains default values

return View(new Person{ Age = 18 });

Another option is to add a singleton static helper to your Person class that returns a default, populated class

  static public Person GetDefaultNew()
        {
            return new Person{ Age = 18 };
        }

Then you need

return View(new Person.GetDefaultNew());
  • You wouldn't need to new up the return from GetDefaultNew() but I see where you're going. In the original question I had simply forgotten to pass any instance of the model along. – Bryan Boettcher Nov 19 '13 at 19:40
  • To extend my answer, I would say that it's worth creating your own "ViewModel" class that has all of the instance data required for the view. This keeps the controller skinny, your model with its annotations, and your view model class with the business rules and other options (such as setting default business values - some of which will not be known without referencing other lists that you will also have in the view model) for the view in question. It also makes your view model highly testable and the view as simple as possible –  Nov 28 '13 at 14:13
0

Setting JSON.net's DefaultValueHandling parameter makes DefaultValue work:

class Person {
    [JsonProperty("Age", DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)]
    [DefaultValue(18)]
    public int Age { get; set; }
}
vcliment89
  • 75
  • 2
  • 14