Introduction
If you are reading this post, I bet you at least once went in #stackoverflow with the hope to find out a solution of the problem that you were stuck with. Other day, while I was surfing #stackoverflow, I have noticed that a good number of developers often faced difficulty while dealing with enum in Asp.Net MVC, their fair amount of code is just not enough to make their enum turn into dropdown list. And this problem was there for years. Obviously, genius developers did not seat idle. They figure out different approaches to deal with this issue and most often these approaches is not fairly simple to follow.
With the release of MVC 5.1 in Feb 27, 2014 there finally came enum support it View. The old school approach still applicable and useable and plenty of such resources could be found on the web but it is not recommended as the new way is much simpler. I am not going to discuss the old way rather I will focus the new way of achieving our purpose.
Software Requirements
You will be in need of any of the following -
- Visual Studio 2012: Download ASP.NET and Web Tools 2013.1 for Visual Studio 2012.
- Visual Studio 2013: Download Visual Studio 2013 Update 1. This update is needed for editing ASP.NET MVC 5.1 Razor Views.
Now, you have the tools, lets get started by creating an Asp.Net Web Application. To demonstrate the enum support we will build a simple student registration form where we expect that a dropdown box will show the Gender, Country from where people can select their desired information.
Initially, for the demonstration purpose I have created the following architecture. You can download the entire source file from here.
Gender enum is fairly simple, it consists with Male and Female and it is defined as
public enum Gender
{
Male,
Female
}
5 countries are added in the enum list. The Country enum is defined as
public enum Country
{
Australia,
Bangladesh,
England,
France,
Usa
}
The student entity [POCO (Plain Old C# object) class] looks like this
public class Student
{
public int Id { get; set; }
public String Name { get; set; }
public Gender Gender { get; set; }
public Country Country { get; set; }
}
Right now, If we just rely on scaffolding to do the hard work for you and generate some view then you will end up like this
If you never deal with enum before this view probably freaks you out, you probably found yourself saying -
" hey wait a minute, scaffolding is not working! its not rendering the view properly "
Right now you probably want to inspect the scaffolding generated code for the view and here it is-
<div class="form-group">
@Html.LabelFor(model => model.Gender, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Gender)
@Html.ValidationMessageFor(model => model.Gender)
</div>
<div class="form-group">
@Html.LabelFor(model => model.Country, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Country)
@Html.ValidationMessageFor(model => model.Country)
</div>
</div>
And everything seems fairly fine. right? There you have the editor extension EditorFor() on the right position and data was also passed properly. Then whats wrong? Well, actually EditorFor() does not know how to render an Enum, so it uses its default settings and render a textbox for the enum.
Don't freak out! We will deal with this issue within a minute. But first update
Microsoft ASP.NET MVC from NuGet. Do it otherwise you would not find the extension method that we are going to use to solve our problem.
Managing NuGet Packages[/caption]
Once you are done change the markup as follows -
@*@Html.EditorFor(model => model.Gender)*@
@Html.EnumDropDownListFor(model=>model.Gender)
Here, we are using the new EnumDropDownListFor() extension method. Implementation is same as EditorFor() extension.
HURRAH! just one line of code saves our live.
Now, lets extend the scenario bit. What if we want to show special character/symbol spaces in the enumdropdowlist. We know Enum does not support spaces/special characters so what we can do is to use Display Attribute. Here in the following scenario we are using [Display(Name="United States")] to show "United States" instead of showing "Usa".
public enum Country
{
Australia,
Bangladesh,
England,
France,
[Display(Name="United States")]
Usa
}
and here is the view. You can see its showing "United States" in the EnumDropDownList.
Note: At this point if you just create a new student selecting the values from EnumDropDownList , when you revisit to see what you have just saved you will find that instead of displaying "United States" , its showing "Usa" in the list. If you don't get my point yet have a look on the following image.
And that something what we probably don't want to display. To deal with we can use some kind of templating mechanism.
We are going to provide the enum template, and its important that we put it in the right folder since we want all Enums to use this by default.
Here is the locaition /Shared/DisplayTemplates where we are going to create the partial view for display scenario and make sure to name it as enum.cshtml . File hierarchy is shown in the following image -
Inside Enum.cshtml copy the following code there and you are done !
@model Enum
@if (EnumHelper.IsValidForEnumHelper(ViewData.ModelMetadata))
{
string displayName = null;
foreach (SelectListItem item in EnumHelper.GetSelectList(ViewData.ModelMetadata, (Enum)Model))
{
if (item.Selected)
{
displayName = item.Text ?? item.Value;
}
}
if (String.IsNullOrEmpty(displayName))
{
if (Model == null)
{
displayName = String.Empty;
}
else
{
displayName = Model.ToString();
}
}
@Html.DisplayTextFor(model => displayName)
}
else
{
@Html.DisplayTextFor(model => model)
}
Run the application once again and you will find your long desired solution on the screen :)
If you can remember, we made some changes in the code that was generated by scaffholding. If you are dealing with a large application where almost each view deals with Enum values then probably it would be hard and time consuming to make changes on several places and such scenario I prefer to write down a EditorTemplates so that the scaffholding generated code can run smoothly without any kind of modification.
Here is the locaition /Shared/EditorTemplates where we are going to create the partial view for display scenario and make sure to name it as enum.cshtml . File hierarchy is shown in the following image -
Inside Enum.cshtml copy the following code and you are good to go with the scaffholding generated code.
@model Enum
@if (EnumHelper.IsValidForEnumHelper(ViewData.ModelMetadata))
{
@Html.EnumDropDownListFor(model => model, htmlAttributes: new { @class = "form-control" })
}
else
{
@Html.TextBoxFor(model => model, htmlAttributes: new { @class = "form-control" })
}
Thats really everything that you should know to deal with Enum in MVC5. Hope you find this post helpful :) .
Additional Resource: