前言
本節我們來講講在ASP.NET Core MVC又為我們提供了哪些方便,之前我們探討過在ASP.NET MVC中下拉框綁定方式,這節我們來再來重點看看枚舉綁定的方式,充分實現你所能想到的場景,滿滿的干貨,你值得擁有。
探討枚舉綁定方式
我們首先給出要綁定的枚舉類。
public enum Language
{
JavaScript,
Java,
C,
Python,
SQL,
Oracle
}
枚舉綁定方式一(@Html.DropDownList)
接下來我們廢話少說直接進入主題。
ViewBag.enums = Enum.GetValues(typeof(Language)).Cast<Language>();
視圖頁面則是得到該ViewBag中的值。
@Html.DropDownList("enumList", new SelectList(ViewBag.enums), new { @class = "btn btn-success dropdown-toggle form-control" })
綁定方式二(@Html.EnumDropDownListFor)
此時我們需要借助強類型視圖來操作,如下控制器代碼
[HttpGet]
public IActionResult Get()
{
var test = new TestViewModel();
return View(test);
}
然后視圖代碼:
@Html.EnumDropDownListFor(model => model.Language, htmlAttributes: new { @class = "form-control" })
然后你會發現在ASP.NET Core MVC中沒有此方法的實現了,具體如下:

所以到此我們研究結束,此方法應該是被.net core mvc團隊已經棄用,我們繼續往下看。
*枚舉綁定方式三(Html.GetEnumSelectList)
(1)單獨綁定枚舉
此時我們去敲@Html時出現Razor視圖智能提示,你會看到如下的方法,該方法應該是在ASP.NET MVC5之后和ASP.NET Core MVC中才有並且該方法的參數是一個Type類型
@Html.GetEnumSelectList()
那么此時我們的視圖代碼就演變成了如下所示。
@{
Layout = null;
}
<!DOCTYPE html>
@using WebApplication1.Enums
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
@Html.GetEnumSelectList(typeof(Language))
</body>
</html>
oh,shit,返回的是SelectListItem,看來沒用對,最終嘗試搞出了下面的方法
@{
Layout = null;
}
<!DOCTYPE html>
@using WebApplication1.Enums
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<select asp-items="@Html.GetEnumSelectList(typeof(Language))"></select>
</body>
</html>

這才是我們最終想要的,我們完全不需要借助強類型視圖來實現,有專門針對枚舉的方法,簡單粗暴,但是要記住千萬別再select上加上 asp-for="" 選項,否則會出現如下錯誤,這個沒在研究了,估計和強類型視圖綁定有關

雖然上述是.net core提供給我們最好的方案,確實很好,但是我們實際要的效果不是這樣,我們來舉一個實際場景,比如如下枚舉類。
public enum PayStatus
{
Create,
WaitPay,
WaitConfirm,
Successed,
Failed,
NoPay
}
如上顯示的是支付的若干狀態,當在視圖上顯示時總不能實現Create,WaitPay,WaitConfirm等吧,誰懂呢,我們想要的是該枚舉的描述信息,結果就演變成了如下這樣。
public enum PayStatus
{
[Display(Name = "新建")]
Create,
[Display(Name = "等待支付")]
WaitPay,
[Display(Name = "等待支付確認")]
WaitConfirm,
[Display(Name = "支付成功")]
Successed,
[Display(Name = "支付失敗")]
Failed,
[Display(Name = "無需支付")]
NoPay
}
此時我們依然借助上述方法來實現,如下只是修改一下枚舉類型即可。
<select asp-items="@Html.GetEnumSelectList(typeof(PayStatus))"></select>

.net core mvc還是強大的很啦,這樣還能解析出來,上述我們是通過直接綁定枚舉來實現,要是通過強類型視圖呢,我們來看下:
(2)強類型視圖綁定枚舉
public class TestViewModel
{
public PayStatus PayStatus { get; set; }
}
該方法有兩個重載,如下:一個用來單獨綁定枚舉,一個用來綁定強類型視圖上的枚舉類型
//
// 摘要:
// Returns a select list for the given enumType.
//
// 參數:
// enumType:
// System.Type to generate a select list for.
//
// 返回結果:
// An System.Collections.Generic.IEnumerable`1 containing the select list for the
// given enumType.
//
// 異常:
// T:System.ArgumentException:
// Thrown if enumType is not an System.Enum or if it has a System.FlagsAttribute.
IEnumerable<SelectListItem> GetEnumSelectList(Type enumType);
//
// 摘要:
// Returns a select list for the given TEnum.
//
// 類型參數:
// TEnum:
// Type to generate a select list for.
//
// 返回結果:
// An System.Collections.Generic.IEnumerable`1 containing the select list for the
// given TEnum.
//
// 異常:
// T:System.ArgumentException:
// Thrown if TEnum is not an System.Enum or if it has a System.FlagsAttribute.
IEnumerable<SelectListItem> GetEnumSelectList<TEnum>() where TEnum : struct;

上述居然還報錯了,還是一意孤行,最終也沒錯誤啊,如下,郁悶。

當然我們也可以在此基礎上在視圖上追加一個默認選項,如下:
<select asp-items="Html.GetEnumSelectList<PayStatus>()">
<option>---no specified----</option>
</select>

當添加中文時,你會驚訝結果亂碼了,這難道是bug么。
<select asp-items="Html.GetEnumSelectList<PayStatus>()">
<option>---"請選擇"----</option>
</select>

不知是何緣故,求解決這個問題,bug??????我覺得不是。。。。
枚舉綁定方式四(TagHelper)
上述第三種方案其實已經夠我們用了,但是有時候實際情況非我們所想象的那樣,在我們項目中對枚舉類的描述是用的如下包
System.ComponentModel.Primitives

所以此時枚舉就變成了如下這樣:
public enum PayStatus
{
[Description("新建")]
Create,
[Description("等待支付")]
WaitPay,
[Description("等待支付確認")]
WaitConfirm,
[Description("支付成功")]
Successed,
[Description("支付失敗")]
Failed,
[Description("無需支付")]
NoPay
}
當利用DisplayName特性時此時是和視圖相結合了的,所以Razor引擎能夠解析出來但是變成Description特性肯定就不好使,如下:

接下來我們只能夠自定義獲取DescriptionAttribute中的值,我們通過TagHelper來實現,如此對於枚舉我們不再有任何限制,隨心所欲。首選我們需要獲取上述特性並取到其值並添加到SelectListItem中,形成一個集合,代碼如下:
public List<SelectListItem> GetEnumSelectListItem()
{
var list = new List<SelectListItem>();
var typeInfo = Value.GetType().GetTypeInfo();
var enumValues = typeInfo.GetEnumValues();
foreach (var value in enumValues)
{
MemberInfo memberInfo =
typeInfo.GetMember(value.ToString()).First();
var descriptionAttribute =
memberInfo.GetCustomAttribute<DescriptionAttribute>();
list.Add(new SelectListItem()
{
Text = descriptionAttribute.Description,
Value = value.ToString()
});
}
return list;
}
接下來我們取出遍歷上述集合中的值並添加到Select中,最終代碼如下:
public class EnumsTagHelper : TagHelper
{
public Enum Value { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
var list = GetEnumSelectListItem();
output.Content.AppendHtml("<select>");
foreach (var item in list)
{
if (item.Value != null)
output.Content.AppendHtml($"<option value='{item.Value}'>{item.Text}</option>");
else
output.Content.AppendHtml($"<option>{item.Text}</option>");
}
output.Content.AppendHtml("<select/>");
}
}
最后就是在視圖中進行調用了,如下:
@using WebApplication1.Enums
@addTagHelper *, WebApplication1
<html>
<head>
<meta name="viewport" charset="utf-8" />
<title>Index</title>
</head>
<body>
<enums Value="@PayStatus.Create"></enums>
</body>
</html>

一切都是那么簡單,你get了沒有。
總結
本節詳細介紹了在ASP.NET Core MVC中如何綁定枚舉的幾種方式,枚舉要一個好的描述從而顯的更有意義,若你是利用DisplayName特性,那就用內置的吧,內部自動會進行解析,若是利用Description特性則可以利用上述TagHelper來實現,你喜歡哪種用哪種,接下來我將繼續利用周末時間更新線程系列文章,也有可能會包括.NET Core文章,關於SQL Server性能優化系列暫時擱置。

