2010-10-20 5 views
1

Existe-t-il un moyen de transmettre automatiquement une collection d'énumérations à une méthode ActionMethod (sur un GET)?Passez la collection d'énumérations à ASP.NET MVC ActionMethod

Par exemple, si j'ai la définition enum suivante:

enum DaysEnum {Sat, Sun, Mon, Tue, Wed, Thu, Fri}; 

et j'ai une définition ActionMethod de:

ActionResult SampleActionMethod (List<DaysEnum> days) 

Est-il possible que je pourrais rendre, dans une vue, une URL qui passerait dans une collection de DayEnums. Quelque chose comme:

var someDays = new List<DaysEnum> {DaysEnum.Sat, DaysEnum.Sun, DaysEnum.Mon}; 

Url.Route(new { days = someDays, controller="whatever", action="SampleActionMethod"}); 

Le modèle de liaison par défaut ne semble pas supporter cela, puisque je reçois actuellement ce qui suit rendu:

http://.../System.Collections.Generic.List`1[DaysEnum] 

Je sais que je peux le faire en aplatissant manuellement la collection par exemple, une chaîne délimitée par des tirets, puis recréer la collection dans la méthode ActionMethod, mais je regardais quelque chose de plus élégant. Divers blogposts parlent de passer dans les collections, mais cela concerne plutôt les POSTS.

Répondre

1
<%= Html.ActionLink("test enums", "SampleActionMethod", new RouteValueDictionary { 
    { "days[0]", DaysEnum.Sun }, { "days[1]", DaysEnum.Mon } 
}) %> 
+0

Merci, cela fonctionne. Le seul problème est que l'URL n'est plus conviviale. Donc, au lieu de http: // contrôleur/action/valeur1/valeur2/..., je sais obtenir http: // contrôleur/action? Param1 = valeur1 & param2 = valeur2 & jours [0] = Sun & days [1] = Mon. Encore, c'est mieux que la liaison manuelle – sohail

0

Je crains que les types de données complexes ne puissent pas être acheminés avec une requête GET. Nous pouvons utiliser certaines valeurs cachées et publier les données si vous voulez envoyer ces valeurs en tant que collection

+1

Il semble que la réponse de Darin fonctionne, mais au détriment d'une URL amicale. – sohail

+2

oui c'est mot mais ça n'envoie pas de types complexes. il plutôt manuellement sérialiser les données qui sont à nouveau remis ensemble par modèle liant –

2

Nous faisons cela en utilisant un classeur de modèle personnalisé pour le paramètre du contrôleur, et une méthode d'extension pour former le paramètre dans l'URL.

Le liant modèle ressemble à ceci:

/// <summary> 
/// Custom binder class. 
/// </summary> 
public class DaysEnumModelBinder : IModelBinder 
{ 
    /// <summary> 
    /// Convert a comma-separated string to a list. 
    /// </summary> 
    /// <param name="rawValue">Raw value from binding context.</param> 
    /// <returns>List of enum values.</returns> 
    public static List<DaysEnum> ConvertArray(object rawValue) 
    { 
     var results = new List<DaysEnum>(); 

     string[] query = rawValue as string[]; 

     if (query != null && query.Length != 0) 
     { 
      string[] parts = query[0].Split(','); 

      foreach (string part in parts) 
      { 
       try 
       { 
        DaysEnum resultValue = (DaysEnum)Enum.Parse(typeof(DaysEnum), part, true); 
        results.Add(resultValue); 
       } 
       catch (ArgumentException) 
       { 
       } 
      } 
     } 

     return results; 
    } 

    /// <summary> 
    /// Implement IModelBinder to bind a comma-separated array of int values to a single array. 
    /// </summary> 
    /// <param name="controllerContext">The controller context.</param> 
    /// <param name="bindingContext">The binding context.</param> 
    /// <returns>Int array where applied to the correct type of object.</returns> 
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     if (!bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName)) 
     { 
      return new DefaultModelBinder().BindModel(controllerContext, bindingContext); 
     } 

     if (bindingContext.ModelType == typeof(DaysEnum[])) 
     { 
      List<DaysEnum> results = ConvertArray(bindingContext.ValueProvider.GetValue(bindingContext.ModelName).RawValue); 

      return results.ToArray(); 
     } 

     return new DefaultModelBinder().BindModel(controllerContext, bindingContext); 
    } 
} 

Ensuite, dans votre méthode de commande vous accrochez le liant comme ceci:

ActionResult MyMethod([ModelBinder(typeof(DaysEnumModelBinder))] DaysEnum[] days) 
{ 
    ... 
} 

Enfin, selon vous render l'URL avec quelque chose comme string.Join(",", days.Select(d => d.ToString())).

+0

Merci. Vous avez essentiellement fait ce que j'essayais d'éviter (à savoir aplatir et déstabiliser manuellement la collection, comme indiqué dans ma question), mais il est utile de savoir que cela peut au moins être encapsulé dans un classeur de modèle personnalisé. Si la solution de Darin n'avait pas fonctionné, j'aurais utilisé quelque chose comme ça. – sohail

+0

Ouais, pour nous l'exigence était d'utiliser un seul paramètre de requête, donc c'était nécessaire. –

Questions connexes