如何接受数组作为 ASP.NET MVC 控制器操作参数?

我有一个名为 Designs的 ASP.net MVC 控制器,它的动作有以下签名:

public ActionResult Multiple(int[] ids)

但是,当我尝试使用 url 导航到这个操作时:

http://localhost:54119/Designs/Multiple?ids=24041,24117

ids参数始终为空。有没有什么方法可以让 MVC 把 ?ids= URL 查询参数转换成动作的数组?我曾经看到过使用动作过滤器的讨论,但据我所知,它只适用于在请求数据中传递数组的 POST,而不适用于 URL 本身。

72050 次浏览

The default model binder expects this url:

http://localhost:54119/Designs/Multiple?ids=24041&ids=24117

in order to successfully bind to:

public ActionResult Multiple(int[] ids)
{
...
}

And if you want this to work with comma separated values you could write a custom model binder:

public class IntArrayModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (value == null || string.IsNullOrEmpty(value.AttemptedValue))
{
return null;
}


return value
.AttemptedValue
.Split(',')
.Select(int.Parse)
.ToArray();
}
}

and then you could apply this model binder to a particular action argument:

public ActionResult Multiple([ModelBinder(typeof(IntArrayModelBinder))] int[] ids)
{
...
}

or apply it globally to all integer array parameters in your Application_Start in Global.asax:

ModelBinders.Binders.Add(typeof(int[]), new IntArrayModelBinder());

and now your controller action might look like this:

public ActionResult Multiple(int[] ids)
{
...
}

You can also use this URL format, and ASP.NET MVC will do everything for you. But, remember to apply URL encoding.

?param1[0]=3344&param1[1]=2222

I don't know where Groky's URL string was coming from, but I had the same problem with some javascript calling my controller/action. It would build up a URL of null, 1, or many "IDs" from a multiple-select list (which is unique to the solution I'm going to share).

I copy/pasted Darin's custom model binder and decorated my action/parameter, but it didn't work. I still got null valued int[] ids. Even in the "safe" case where I actually did have many IDs.

I ended up changing the javascript to produce an ASP.NET MVC friendly parameter array like

?ids=1&ids=2

I had to do some silly stuff, though

ids || []                 #=> if null, get an empty array
[ids || []]               #=> if a single item, wrap it in an array
[].concat.apply([], ...)  #=> in case I wrapped an array, flatten it

So, the full block was

ids = [].concat.apply([], [ids || []])
id_parameter = 'ids=' + ids.join('&ids=')

It's messy, but it's the first time I had to hack like this in javascript.

To extend on Darin Dimitrov's answer, something you can get away with is accepting a simple string in your URL parameter and converting it to an array yourself:

public ActionResult Multiple(string ids){
int[] idsArray = ids.Split(',').Select(int.Parse).ToArray();
/* ...process results... */
}

If you get a parse error while doing this (because someone passed you a malformed array), you can cause your exception handler to return a 400 Bad Request error instead of the default, more unfriendly 404 Not Found error that MVC returns when an endpoint is not found.

.Net Core Answer

For those coming here in recent times, you can do this in .Net Core with:

http://localhost:54119/Designs/Multiple?ids=24041&ids=24117

and:

public ActionResult Multiple([FromQuery] int[] ids)
{
...
}