【问题标题】:Pass collection of enums to ASP.NET MVC ActionMethod将枚举集合传递给 ASP.NET MVC ActionMethod
【发布时间】:2010-10-20 17:46:56
【问题描述】:

有没有办法自动将枚举集合传递给 ActionMethod(在 GET 上)?

例如,如果我有以下枚举定义:

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

而且,我有一个 ActionMethod 定义:

ActionResult SampleActionMethod ( List<DaysEnum> days)

有没有一种方法可以在视图中呈现一个可以传入 DayEnums 集合的 URL。比如:

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

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

默认模型绑定器似乎不支持这一点,因为我目前正在渲染以下内容:

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

我知道我可以通过手动将集合展平为例如用破折号分隔的字符串来做到这一点,然后在 ActionMethod 中重新创建集合,但我正在寻找更优雅的东西。各种 blog posts 谈论传递集合,但这更多是关于在做 POSTS 时。

【问题讨论】:

    标签: asp.net asp.net-mvc-2 c#-4.0


    【解决方案1】:

    我们为控制器参数使用自定义模型绑定器,以及在 URL 中形成参数的扩展方法。

    模型绑定器如下所示:

    /// <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);
        }
    }
    

    然后在你的控制器方法中你像这样连接活页夹:

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

    最后在您的视图中使用string.Join(",", days.Select(d =&gt; d.ToString())) 之类的内容呈现 URL。

    【讨论】:

    • 谢谢。您基本上已经完成了我试图避免的事情(即手动展平和去展平集合,如我的问题中所述),但知道这至少可以封装在自定义模型绑定器中很有用。如果达林的解决方案没有奏效,我会使用这样的东西。
    • 是的,对我们来说要求是使用单个请求参数,所以这是必要的。
    【解决方案2】:
    <%= Html.ActionLink("test enums", "SampleActionMethod", new RouteValueDictionary { 
        { "days[0]", DaysEnum.Sun }, { "days[1]", DaysEnum.Mon } 
    }) %>
    

    【讨论】:

    【解决方案3】:

    恐怕GET请求不能携带复杂的数据类型。如果您确实想将这些值作为集合发送,您可以使用一些隐藏值并发布数据

    【讨论】:

    • 达林的回答似乎有效,但以友好的 URL 为代价。
    • 是的,它确实是 word,但它不发送复杂类型。而是手动序列化由模型绑定器再次组合在一起的数据
    猜你喜欢
    • 1970-01-01
    • 2011-05-10
    • 2014-11-22
    • 2015-01-07
    • 2011-08-03
    • 1970-01-01
    • 2022-01-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多