Cleaning Up ASP.NET Data Display Using Component Model Attributes
In my last article, I talked about how you can use ASP.NET Editor Templates and Display Templates with the Html helper methods to keep your display logic understandable, maintainable, and organized. If you ran the sample application (or looked at some of the screenshots in the article) you might have noticed that the formatting of the field names was kind of messed up. For example, "LastName
" instead of "Last Name
" and "FirstName
" instead of "First Name
."
[Click on image for larger view.]
The reason that that is happening is because I'm using an ASP.NET helper method called DisplayNameFor()
. Here's the code that creates that table header row that you see in the screenshot above.
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Id)
</th>
<th>
@Html.DisplayNameFor(model => model.LastName)
</th>
<th>
@Html.DisplayNameFor(model => model.FirstName)
</th>
<th></th>
</tr>
</thead>
...
</table>
Those calls to DisplayNameFor()
use some compiler and/or reflection magic to grab the name of the property and turn it into a label string.
DisplayNameFor(): Sure, It's Cool ... but the Value Is Wrong
So DisplayNameFor()
turns the property name into a label string. I suppose it's nice because it's compile-time checkable and it uses a compiled value rather than a hardcoded string for the label ... but the label is wrong. If you're using this for a not-that-important application, having a wrong label value might be fine ... but what if you want to use this in a production application?
What if you want the label to be "Last Name
" instead of "LastName
"? That helper method is just taking the property name and converting it to a string and C# doesn't allow you to have spaces in a property name so renaming the property to be "Last Name
" isn't going to work.
public class Person
{
public string Id { get; set; } = Guid.NewGuid().ToString();
public string FirstName { get; set; } = string.Empty;
public string LastName { get; set; } = string.Empty;
public List<Address> Addresses { get; set; } = new();
}
Component Model Data Annotations to the Rescue!
If you want to start controlling what DisplayNameFor() outputs, there are some attributes that you'll want to check out. This brings us to the System.ComponentModel.DataAnnotations namespace.
If you want to customize the display name of a property, you can decorate it with the [Display()]
attribute. The following code sample is the Person
class modified to use the Display
attribute.
using System.ComponentModel.DataAnnotations;
namespace Benday.AspNetTemplateDemo.Api;
public class Person
{
public string Id { get; set; } = Guid.NewGuid().ToString();
[Display(Name = "First Name")]
public string FirstName { get; set; } = string.Empty;
[Display(Name = "Last Name")]
public string LastName { get; set; } = string.Empty;
public List<Address> Addresses { get; set; } = new();
}
Now when I run the application, any place in the code that uses DisplayNameFor()
now picks up the [Display]
attribute value instead of simply using the raw property name.
[Click on image for larger view.]
Using Attributes to Format Data Values
So far in this article, I've talked about just DisplayNameFor()
label values. But there are about a half-zillion other attributes in System.ComponentModel.DataAnnotations
that can be used for other kinds of data formatting.
The two formatting things that I run into a lot are 1) formatting dates and 2) formatting decimals.
To demonstrate these, I'm going to add a handful of additional properties to the Person
class:
BirthDate
HeightInInches
HeightInCentimeters
public class Person
{
public string Id { get; set; } = Guid.NewGuid().ToString();
[Display(Name = "First Name")]
public string FirstName { get; set; } = string.Empty;
[Display(Name = "Last Name")]
public string LastName { get; set; } = string.Empty;
public List<Address> Addresses { get; set; } = new();
[Display(Name = "Birth Date")]
public DateTime BirthDate { get; set; } = DateTime.UtcNow;
[Display(Name = "Height (in))")]
public float HeightInInches { get; set; } = 69.549281f;
[Display(Name = "Height (cm)")]
public float HeightInCentimeters
{
get
{
return HeightInInches * 2.54f;
}
}
}
I've added these to the Edit Person page in /Views/Person/Edit.cshtml
using the <input asp-for=" ... "
syntax. BTW, in case you're wondering, that's pretty much the equivalent of doing @Html.EditorFor()
.
<div class="form-group mb-3">
<label asp-for="BirthDate" class="control-label"></label>
<input type="text" asp-for="BirthDate" class="form-control" />
<span asp-validation-for="BirthDate" class="text-danger"></span>
</div>
<div class="form-group mb-3">
<label asp-for="HeightInInches" class="control-label"></label>
<input asp-for="HeightInInches" class="form-control" />
<span asp-validation-for="HeightInInches" class="text-danger"></span>
</div>
<div class="form-group mb-3">
<label asp-for="HeightInCentimeters" class="control-label"></label>
<input asp-for="HeightInCentimeters" class="form-control" />
<span asp-validation-for="HeightInCentimeters" class="text-danger"></span>
</div>
Now when I go to the Edit Person
page, I see those fields. But the values are kind of ugly. For BirthDate
, I don't need all the time information and for the height fields, there are just way too many digits to the right of the decimal point.
[Click on image for larger view.]
To clean this up and adjust the formatting for the DateTime
and float
fields on Person
, you need to add [DisplayFormat]
attributes to those properties. The DisplayFormat
attribute takes a data format string just like what you'd use if you were calling the ToString()
method on an object.
If you want to format a DateTime
to display just the date, the format string is {0:d}
. To display a float with two decimal places, the format string is {0:F2}
. Applying those changes to the Person
class gives the following code.
public class Person
{
public string Id { get; set; } = Guid.NewGuid().ToString();
[Display(Name = "First Name")]
public string FirstName { get; set; } = string.Empty;
[Display(Name = "Last Name")]
public string LastName { get; set; } = string.Empty;
public List<Address> Addresses { get; set; } = new();
[Display(Name = "Birth Date")]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:d}")]
public DateTime BirthDate { get; set; } = DateTime.UtcNow;
[Display(Name = "Height (in))")]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:F2}")]
public float HeightInInches { get; set; } = 69.549281f;
[Display(Name = "Height (cm)")]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:F2}")]
public float HeightInCentimeters
{
get
{
return HeightInInches * 2.54f;
}
}
}
When you run the application, now you get input boxes that display the data using those format strings.
[Click on image for larger view.]
Summary
Pretty cool, huh? There are so many things in the System.ComponentModel.DataAnnotations
namespace to look in to and it's another one of those 'hidden in plain sight' features of ASP.NET Core.
If you want to check out the source code, it's available here
About the Author
Benjamin Day is a consultant, trainer and author specializing in software development, project management and leadership.
Posted by Benjamin Day on 04/21/2025