ASP.Net MVC RouteData et matrices

Si j'ai une Action comme ceci:

public ActionResult DoStuff(List<string> stuff)
{
   ...
   ViewData["stuff"] = stuff;
   ...
   return View();
}

je peux le frapper avec l'URL suivante:

http://mymvcapp.com/controller/DoStuff?stuff=hello&stuff=world&stuff=foo&stuff=bar

Mais dans mon ViewPage, j'ai ce code:

<%= Html.ActionLink("click here", "DoMoreStuff", "MoreStuffController", new { stuff = ViewData["stuff"] }, null) %>

malheureusement, MVC n'est pas assez intelligent pour reconnaître que l'action prend un tableau, et décompose la liste pour former la route d'url appropriée. au lieu de cela il fait juste un .ToString() sur l'objet qui vient de listes le type de données dans le cas d'une Liste.

y a-t-il un moyen D'obtenir du Html?ActionLink à générer une URL appropriée lorsque l'un des paramètres de l'Action de destination est un tableau ou une liste?

-- edit --

comme Josh l'a souligné ci-dessous, ViewData["stuff"] est juste un objet. J'ai essayé de simplifier le problème, mais plutôt causé aucun bug! J'utilise en fait une page de vue dédiée donc j'ai un modèle de type conscient étroitement couplé. Le ActionLink en fait ressemble à:

<%= Html.ActionLink("click here", "DoMoreStuff", "MoreStuffController", new { stuff = ViewData.Model.Stuff }, null) %>

Où ViewData.Modèle.Trucs est tapé sous la forme d'une Liste

24
demandé sur puffpio 2009-11-18 02:56:31

6 réponses

je pense qu'un Helper HTML personnalisé serait approprié.

 public static string ActionLinkWithList( this HtmlHelper helper, string text, string action, string controller, object routeData, object htmlAttributes )
 {
     var urlHelper = new UrlHelper( helper.ViewContext.RequestContext );


     string href = urlHelper.Action( action, controller );

     if (routeData != null)
     {
         RouteValueDictionary rv = new RouteValueDictionary( routeData );
         List<string> urlParameters = new List<string>();
         foreach (var key in rv.Keys)
         {
             object value = rv[key];
             if (value is IEnumerable && !(value is string))
             {
                 int i = 0;
                 foreach (object val in (IEnumerable)value)
                 {
                     urlParameters.Add( string.Format( "{0}[{2}]={1}", key, val, i ));
                     ++i;
                 }
             }
             else if (value != null)
             {
                 urlParameters.Add( string.Format( "{0}={1}", key, value ) );
             }
         }
         string paramString = string.Join( "&", urlParameters.ToArray() ); // ToArray not needed in 4.0
         if (!string.IsNullOrEmpty( paramString ))
         {
            href += "?" + paramString;
         }
     }

     TagBuilder builder = new TagBuilder( "a" );
     builder.Attributes.Add("href",href);
     builder.MergeAttributes( new RouteValueDictionary( htmlAttributes ) );
     builder.SetInnerText( text );
     return builder.ToString( TagRenderMode.Normal );
}
20
répondu tvanfosson 2011-06-27 22:57:44

vous pouvez suffixe routevalues avec un index de tableau comme ceci:

RouteValueDictionary rv = new RouteValueDictionary();
rv.Add("test[0]", val1);
rv.Add("test[1]", val2);

il en résultera le querystring contenant test=val1&test=val2

cela pourrait aider ?

4
répondu Moes 2017-05-02 01:00:31

combiner les deux méthodes fonctionne bien.

public static RouteValueDictionary FixListRouteDataValues(RouteValueDictionary routes)
{
    var newRv = new RouteValueDictionary();
    foreach (var key in routes.Keys)
    {
        object value = routes[key];
        if (value is IEnumerable && !(value is string))
        {
            int index = 0;
            foreach (string val in (IEnumerable)value)
            {
                newRv.Add(string.Format("{0}[{1}]", key, index), val);
                index++;
            }
        }
        else
        {
            newRv.Add(key, value);
        }
    }

    return newRv;
}

puis utilisez cette méthode dans toute méthode d'extension qui nécessite des valeurs de routage avec IEnumerable(s) en elle.

malheureusement, ce contournement semble nécessaire dans MVC3 aussi.

3
répondu Emanuel 2017-05-02 01:01:35

Il y a un librarly appelé extraction de document, que vous pouvez utiliser pour insérer des objets complexes dans les routes/url.

Il fonctionne comme ceci:

using Unbound;

Unbinder u = new Unbinder();
string url = Url.RouteUrl("routeName", new RouteValueDictionary(u.Unbind(YourComplexObject)));
0
répondu Jenny O'Reilly 2014-05-23 08:57:14

ceci servira simplement de prolongement à la UrlHelper et il suffit de fournir une belle url prêt à mettre n'importe où plutôt que d'un ensemble d'une balise, il va aussi préserver la plupart de l'itinéraire d'autres valeurs pour toute autre url en cours d'utilisation... en vous donnant l'url spécifique la plus conviviale que vous avez (moins les valeurs IEnumerable) et puis juste ajouter les valeurs de la chaîne de requête à la fin.

public static string ActionWithList(this UrlHelper helper, string action, object routeData)
{

    RouteValueDictionary rv = new RouteValueDictionary(routeData);

    var newRv = new RouteValueDictionary();
    var arrayRv = new RouteValueDictionary();
    foreach (var kvp in rv)
    {
        var nrv = newRv;
        var val = kvp.Value;
        if (val is IEnumerable && !(val is string))
        {
            nrv = arrayRv;
        }

        nrv.Add(kvp.Key, val);

    }


    string href = helper.Action(action, newRv);

    foreach (var kvp in arrayRv)
    {
        IEnumerable lst = kvp.Value as IEnumerable;
        var key = kvp.Key;
        foreach (var val in lst)
        {
            href = href.AddQueryString(key, val);
        }

    }
    return href;
}

public static string AddQueryString(this string url, string name, object value)
{
    url = url ?? "";

    char join = '?';
    if (url.Contains('?'))
        join = '&';

    return string.Concat(url, join, name, "=", HttpUtility.UrlEncode(value.ToString()));
}   
0
répondu tocsoft 2017-05-02 01:02:20

Je ne suis pas à mon poste de travail, mais que diriez-vous de quelque chose comme:

<%= Html.ActionLink("click here", "DoMoreStuff", "MoreStuffController", new { stuff = (List<T>)ViewData["stuff"] }, null) %>

ou le tapé:

<%= Html.ActionLink("click here", "DoMoreStuff", "MoreStuffController", new { stuff = (List<T>)ViewData.Model.Stuff }, null) %>
-2
répondu Chaddeus 2009-11-18 00:56:27