I have an ASP.Net Core 2.2 MVC application and I'm looking for some help with a specific case.
I have setup localization with resource files for 8 languages and this is working fine, both server and client side including the translation of Enum values with
<select asp-items="@Html.GetEnumSelectList<Status>()" ...
I am however struggling with the following case: in a certain view I don't want to show all the values of an Enum so I am iterating through the Enum values in the constructor of the model that I pass to the view and build a SelectList.
public class BranchViewModel
{
public MdxBranch Branch { get; set; }
public List<SelectListItem> Status { get; set; }
public BranchViewModel()
{
// Create a SelectList for Status skipping or disabling certain enum values
Status = new List<SelectListItem>();
foreach (var enumItem in Enum.GetValues(typeof(Status)))
{
if (enumItem.GetHashCode() == (int)Status.SystemHidden || enumItem.GetHashCode() == (int)Status.ToVerify)
{
continue; // skip this value
}
SelectListItem sli = new SelectListItem()
{
Value = enumItem.GetHashCode().ToString(),
// get the Display Name
Text = EnumExtension.GetDisplayAttribute((Status)enumItem)
};
Status.Add(sli);
}
}
}
To fill the Text of a SelectListItem I'm calling an extension that should retrieve the localized DisplayAttribute (which I found as a solution in the many articles I have read about this)
The Extension method
public static class EnumExtension
{
public static string GetDisplayAttribute(this Enum value)
{
return
value
.GetType()
.GetMember(value.ToString())
.FirstOrDefault()
?.GetCustomAttribute<DisplayAttribute>()
?.GetName()
?? value.ToString();
}
}
When in debug I can see that every enum value is found but that it always returns the default display name as in the Enum definition. Again, if I use the Enum in a view with @Html.GetEnumSelectList then it generates a translated list.
The Enum definition
public enum Status
{
[Display(Name = "Open")]
Open,
[Display(Name = "Locked")]
Locked,
[Display(Name = "Offline")]
Offline,
[Display(Name = "Archived")]
Archived,
[Display(Name = "To verify")]
ToVerify,
[Display(Name = "System, hidden")]
SystemHidden = 9
}
In the view I'm displaying the result with a select-tag
<select asp-for="Branch.Status" asp-items="Model.Status" class="form-control" ..."></select>
The one thing I was thinking about is the way that I pass the Enum to the extension method where I convert the current item from Enum.GetValues back into an Enum:
Text = EnumExtension.GetDisplayAttribute((Status)enumItem)
The Enum defintion is not in the main project of the solution, where the view and controller reside, and the translation is made with a shared resource file for the project (not the solution). The extension method is in the same project/namespace as the Enum definition.
Any guidance would be greatly appreciated.
EDIT 1. added the select tag used to display the Enum in the view
EDIT 2. fixed the typo with MdxStatus/Status
EDIT 3. I tried translating the DisplayAttribute of a 1 option of the Enum using a variable of the Enum type but also that didn't return a translation.
For testing I added the following code in the foreach loop:
Status statusOpen = Status.Open;
var abc = statusOpen
.GetType()
.GetMember(statusOpen.ToString())
.FirstOrDefault()
?.GetCustomAttribute<DisplayAttribute>()
?.GetName();
The result in abc is the default value of the Name attribute. For debugging purposes I then broke down the Fluent syntax into its individual pieces so I could track what was happening.
var gT = statusOpen.GetType();
var gM = gT.GetMember(statusOpen.ToString());
var fD = gM.FirstOrDefault();
var gCA = fD.GetCustomAttribute<DisplayAttribute>();
var gN = gCA.GetName();
Again the result in gN is the default value of the Name attribute. I saw 2 errors in debug, 1 for gT (GetType) and 1 for gM (getMember)
GetType
Name: DeclaringMethod
Value: '((System.RuntimeType)gT).DeclaringMethod' threw an exception of type
'System.InvalidOperationException'
Type: System.Reflection.MethodBase {System.InvalidOperationException}
GetMember
Name: FieldHandle
Value: '((System.Reflection.MdFieldInfo)gM[0]).FieldHandle' threw an exception of type 'System.NotSupportedException'
Type: System.RuntimeFieldHandle {System.NotSupportedException}
I am not sure if these errors are part of the issue.
<select asp-for="Branch.Status" asp-items="Model.Status" class="form-control" ..."></select>, then the listitems are not translated?