ASP.NET MVC controller actions with changing user parameters?

I want to configure an ASP.NET MVC route that looks like this:

routes.MapRoute( "Default", // Route name "{controller}/{action}/{idl}", // URL with parameters new { controller = "Home", action = "Index", idl = UrlParameter.Optional } // Parameter defaults ); 

This routes requests that look like this:

 Example/GetItems/1,2,3 

... to my controller action:

 public class ExampleController : Controller { public ActionResult GetItems(List<int> id_list) { return View(); } } 

The question is, what did I configure to convert the idl url parameter from string to List<int> and called the corresponding controller action?

I saw here a question that used OnActionExecuting to preprocess the string, but did not change the type. I don’t think this will work for me here, because when I override OnActionExecuting in my controller and check the ActionExecutingContext parameter, I see that the ActionParameters dictionary already has an idl key with a null value - presumably an attempt to flush from a string to List<int> ... this is the routing part that I want to control.

Is it possible?

+3
source share
2 answers

A good version is to implement your own model binding. Here you can find a sample.

I am trying to give you an idea:

 public class MyListBinder : IModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { string integers = controllerContext.RouteData.Values["idl"] as string; string [] stringArray = integers.Split(','); var list = new List<int>(); foreach (string s in stringArray) { list.Add(int.Parse(s)); } return list; } } public ActionResult GetItems([ModelBinder(typeof(MyListBinder))]List<int> id_list) { return View(); } 
+8
source

According to slfan, a suitable device is a binder. Here is another approach from my blog that is generic and supports multiple data types. It also elegantly reverts to the default model binding implementation:

 public class CommaSeparatedValuesModelBinder : DefaultModelBinder { private static readonly MethodInfo ToArrayMethod = typeof(Enumerable).GetMethod("ToArray"); protected override object GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder) { if (propertyDescriptor.PropertyType.GetInterface(typeof(IEnumerable).Name) != null) { var actualValue = bindingContext.ValueProvider.GetValue(propertyDescriptor.Name); if (actualValue != null && !String.IsNullOrWhiteSpace(actualValue.AttemptedValue) && actualValue.AttemptedValue.Contains(",")) { var valueType = propertyDescriptor.PropertyType.GetElementType() ?? propertyDescriptor.PropertyType.GetGenericArguments().FirstOrDefault(); if (valueType != null && valueType.GetInterface(typeof(IConvertible).Name) != null) { var list = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(valueType)); foreach (var splitValue in actualValue.AttemptedValue.Split(new[] { ',' })) { list.Add(Convert.ChangeType(splitValue, valueType)); } if (propertyDescriptor.PropertyType.IsArray) { return ToArrayMethod.MakeGenericMethod(valueType).Invoke(this, new[] { list }); } else { return list; } } } } return base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder); } } 
+3
source

All Articles