שליחת ערך מסוג enum ל - Controller ב - asp.net mvc
לאחרונה התחלתי לעבוד עם asp.net mvc, אני מגלה בו הרבה דברים מעניינים שאכתוב עליהם בתקופה הקרובה,
במשימה האחרונה שלי ניסיתי לכתוב action ב - controller שמקבל כפרמטר ערך עבור enum, הקוד היה נראה כך:
בצד ה - controller
public enum MyEnum
{
A = 0,
B = 1,
C = 2
}
public ActionResult Save(MyEnum myEnum)
{
return Json(myEnum);
}
בצד ה - view
<input type="button" value="Save" onclick="save()" />
<script>
function save() {
$.ajax(
{
url: '@Url.Action("Save")',
type: "post",
data: '{myEnum : 2}',
contentType: "application/json"
});
}
</script>
לרוע המזל כל הזמן קבלתי את השגיאה הבאה:
The parameters dictionary contains a null entry for parameter 'myEnum' of non-nullable type 'MvcApplication1.Controllers.MyEnum' for method 'System.Web.Mvc.ActionResult Save(MvcApplication1.Controllers.MyEnum)' in 'MvcApplication1.Controllers.HomeController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
Parameter name: parameters
מעיון קצר בשגיאה אפשר להבין שאיכשהו הערך עבור המשתנה myEnum לא הצליח להגיע לשרת.
לאחר קצת דיבגגינג (הפעלה של Thrown תחת Debug -> Exception) והורדת הסימון של Enable Just My Code (תחת Tools -> Options -> Debugging)
קבלתי את הודעת השגיאה האמיתית
The parameter conversion from type 'System.Int32' to type 'MvcApplication1.Controllers.MyEnum' failed because no type converter can convert between these types.
זה כבר יותר מעניין, ממתי אי אפשר להמיר בין ערך מספרי (int) לבין enum.
לאחר חיפוש בגוגל הגעתי למקום כלשהו ברשת (לצערי אני לא מוצא אותו שוב כדי לתת קרדיט) שכתב את דוגמת הקוד הבאה.
public class EnumBinder<T> : IModelBinder
{
private T DefaultValue { get; set; }
#region ctor
public EnumBinder(T defaultValue)
{
DefaultValue = defaultValue;
}
#endregion ctor
#region IModelBinder Members
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
return bindingContext.ValueProvider.GetValue(bindingContext.ModelName) == null
? DefaultValue :
GetEnumValue<T>(DefaultValue, bindingContext.ValueProvider.GetValue(bindingContext.ModelName)
.AttemptedValue);
}
#endregion
public static T GetEnumValue<TT>(T defaultValue, string value)
{
try
{
T enumType = defaultValue;
enumType = (T)Enum.Parse(typeof(TT), value, true);
return enumType;
}
catch (Exception ex)
{
return defaultValue;
}
}
public static bool Contains(Type enumType, string value)
{
return Enum.GetNames(enumType).Contains(value, StringComparer.OrdinalIgnoreCase);
}
}
לא נעבור על הקוד, בגדול הוא יודע לקבל את הערך שנשלח ולהמיר אותו, כל מה שצריך לעשות זה לרשום אותו ב - Application_Strart
ModelBinders.Binders.Add(typeof(MyEnum), new EnumBinder<MyEnum>(MyEnum.A));