ASP.NET MVC - передать объект массива как значение маршрута в Html.ActionLink (...) - PullRequest
38 голосов
/ 04 апреля 2009

У меня есть метод, который возвращает массив (string []), и я пытаюсь передать этот массив строк в Action Link, чтобы он создал строку запроса, похожую на:

/Controller/Action?str=val1&str=val2&str=val3...etc

Но когда я передаю new {str = GetStringArray ()}, я получаю следующий URL:

/Controller/Action?str=System.String%5B%5D

Так что, в основном, он берет мою строку [] и запускает .ToString (), чтобы получить значение.

Есть идеи? Спасибо!

Ответы [ 6 ]

13 голосов
/ 05 апреля 2009

Попробуйте создать RouteValueDictionary, содержащий ваши значения. Вы должны будете дать каждой записи свой ключ.

<%  var rv = new RouteValueDictionary();
    var strings = GetStringArray();
    for (int i = 0; i < strings.Length; ++i)
    {
        rv["str[" + i + "]"] = strings[i];
    }
 %>

<%= Html.ActionLink( "Link", "Action", "Controller", rv, null ) %>

даст вам ссылку типа

<a href='/Controller/Action?str=val0&str=val1&...'>Link</a>

РЕДАКТИРОВАТЬ : MVC2 изменил интерфейс ValueProvider, чтобы сделать мой первоначальный ответ устаревшим. В качестве свойства следует использовать модель с массивом строк.

public class Model
{
    public string Str[] { get; set; }
}

Тогда механизм связывания заполнит вашу модель значениями, которые вы передадите в URL.

public ActionResult Action( Model model )
{
    var str0 = model.Str[0];
}
2 голосов
/ 23 мая 2014

Еще одно решение, которое мне пришло в голову:

string url = "/Controller/Action?iVal=5&str=" + string.Join("&str=", strArray); 

Это грязно, и вы должны проверить его перед использованием, но, тем не менее, оно должно работать. Надеюсь, это поможет.

2 голосов
/ 14 февраля 2014

Это действительно раздражало меня, так что вдохновение от Скотта Хансельмана Я написал следующий (свободный) метод расширения:

public static RedirectToRouteResult WithRouteValue(
    this RedirectToRouteResult result, 
    string key, 
    object value)
{
    if (value == null)
        throw new ArgumentException("value cannot be null");

    result.RouteValues.Add(key, value);

    return result;
}

public static RedirectToRouteResult WithRouteValue<T>(
    this RedirectToRouteResult result, 
    string key, 
    IEnumerable<T> values)
{
    if (result.RouteValues.Keys.Any(k => k.StartsWith(key + "[")))
        throw new ArgumentException("Key already exists in collection");

    if (values == null)
        throw new ArgumentNullException("values cannot be null");

    var valuesList = values.ToList();

    for (int i = 0; i < valuesList.Count; i++)
    {
        result.RouteValues.Add(String.Format("{0}[{1}]", key, i), valuesList[i]);
    }

    return result;
}

Звоните так:

return this.RedirectToAction("Index", "Home")
           .WithRouteValue("id", 1)
           .WithRouteValue("list", new[] { 1, 2, 3 });
1 голос
/ 23 мая 2014

Существует библиотека с именем Unbinder , которую можно использовать для вставки сложных объектов в маршруты / URL-адреса.

Работает так:

using Unbound;

Unbinder u = new Unbinder();
string url = Url.RouteUrl("routeName", new RouteValueDictionary(u.Unbind(YourComplexObject)));
0 голосов
/ 19 сентября 2017

Это решающий массив HelperExtension и проблемы с IEnumerable:

public static class AjaxHelperExtensions
{
    public static MvcHtmlString ActionLinkWithCollectionModel(this AjaxHelper ajaxHelper, string linkText, string actionName, object model, AjaxOptions ajaxOptions, IDictionary<string, object> htmlAttributes)
    {
        var rv = new RouteValueDictionary();

        foreach (var property in model.GetType().GetProperties())
        {
            if (typeof(ICollection).IsAssignableFrom(property.PropertyType))
            {
                var s = ((IEnumerable<object>)property.GetValue(model));
                if (s != null && s.Any())
                {
                    var values = s.Select(p => p.ToString()).Where(p => !string.IsNullOrEmpty(p)).ToList();
                    for (var i = 0; i < values.Count(); i++)
                        rv.Add(string.Concat(property.Name, "[", i, "]"), values[i]);
                }
            }
            else
            {
                var value = property.GetGetMethod().Invoke(model, null) == null ? "" : property.GetGetMethod().Invoke(model, null).ToString();
                if (!string.IsNullOrEmpty(value))
                    rv.Add(property.Name, value);
            }
        }
        return System.Web.Mvc.Ajax.AjaxExtensions.ActionLink(ajaxHelper, linkText, actionName, rv, ajaxOptions, htmlAttributes);
    }
}
0 голосов
/ 05 апреля 2009

Я бы использовал POST для массива. Помимо того, что вы уродливы и злоупотребляете GET, вы рискуете исчерпать пространство URL (хотите верьте, хотите нет).

Предполагая ограничение 2000 байт . Издержки строки запроса (& str =) сокращают до ~ 300 байт фактических данных (при условии, что остальная часть URL-адреса равна 0 байтам).

...