加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

asp.net-mvc – 传递给Html.ActionLink时在模型上序列化IList属

发布时间:2020-12-16 03:47:53 所属栏目:asp.Net 来源:网络整理
导读:我正在尝试使用以下viewmodel生成 Html.ActionLink: public class SearchModel{ public string KeyWords {get;set;} public IListstring Categories {get;set;}} 要生成我的链接,我使用以下调用: @Html.ActionLink("Index","Search",Model) 其中Model是Sea
我正在尝试使用以下viewmodel生成 Html.ActionLink:

public class SearchModel
{
    public string KeyWords {get;set;}
    public IList<string> Categories {get;set;}
}

要生成我的链接,我使用以下调用:

@Html.ActionLink("Index","Search",Model)

其中Model是SearchModel的一个实例

生成的链接是这样的:

http://www.test.com/search/index?keywords=bla&categories=System.Collections.Generic.List

因为它显然只是在每个属性上调用ToString方法.

我想看到的是:

http://www.test.com/search/index?keywords=bla&categories=Cat1&categories=Cat2

有什么方法可以通过使用Html.ActionLink实现这一点

解决方法

在MVC 3中,你只是运气不好,因为路由值存储在RouteValueDictionary中,顾名思义在内部使用了一个Dictionary,这使得不可能有多个值与一个键相关联.路由值可能应存储在NameValueCollection中,以支持与查询字符串相同的行为.

但是,如果您可以对类别名称施加一些约束,并且您能够以以下格式支持查询字符串:

http://www.test.com/search/index?keywords=bla&categories=Cat1|Cat2

那么你理论上可以将它插入Html.ActionLink,因为MVC使用TypeDescriptor,而TypeDescriptor在运行时又是可扩展的.提供以下代码以证明它是可能的,但我不建议使用它,至少在没有进一步重构的情况下.

话虽如此,您需要首先关联自定义类型描述提供程序:

[TypeDescriptionProvider(typeof(SearchModelTypeDescriptionProvider))]
public class SearchModel
{
    public string KeyWords { get; set; }
    public IList<string> Categories { get; set; }
}

提供程序的实现和覆盖Categories属性的属性描述符的自定义描述符:

class SearchModelTypeDescriptionProvider : TypeDescriptionProvider
{
    public override ICustomTypeDescriptor GetTypeDescriptor(
        Type objectType,object instance)
    {
        var searchModel = instance as SearchModel;
        if (searchModel != null)
        {
            var properties = new List<PropertyDescriptor>();

            properties.Add(TypeDescriptor.CreateProperty(
                objectType,"KeyWords",typeof(string)));
            properties.Add(new ListPropertyDescriptor("Categories"));

            return new SearchModelTypeDescriptor(properties.ToArray());
        }
        return base.GetTypeDescriptor(objectType,instance);
    }
}
class SearchModelTypeDescriptor : CustomTypeDescriptor
{
    public SearchModelTypeDescriptor(PropertyDescriptor[] properties)
    {
        this.Properties = properties;
    }
    public PropertyDescriptor[] Properties { get; set; }
    public override PropertyDescriptorCollection GetProperties()
    {
        return new PropertyDescriptorCollection(this.Properties);
    }
}

然后我们需要自定义属性描述符能够返回由MVC在内部调用的GetValue中的自定义值:

class ListPropertyDescriptor : PropertyDescriptor
{
    public ListPropertyDescriptor(string name)
        : base(name,new Attribute[] { }) { }

    public override bool CanResetValue(object component)
    {
        return false;
    }
    public override Type ComponentType
    {
        get { throw new NotImplementedException(); }
    }
    public override object GetValue(object component)
    {
        var property = component.GetType().GetProperty(this.Name);
        var list = (IList<string>)property.GetValue(component,null);
        return string.Join("|",list);
    }
    public override bool IsReadOnly { get { return false; } }
    public override Type PropertyType
    {
        get { throw new NotImplementedException(); }
    }
    public override void ResetValue(object component) { }
    public override void SetValue(object component,object value) { }
    public override bool ShouldSerializeValue(object component)
    {
        throw new NotImplementedException();
    }
}

最后证明它适用于模仿MVC路由值创建的示例应用程序:

static void Main(string[] args)
{
    var model = new SearchModel { KeyWords = "overengineering" };

    model.Categories = new List<string> { "1","2","3" };

    var properties = TypeDescriptor.GetProperties(model);

    var dictionary = new Dictionary<string,object>();
    foreach (PropertyDescriptor p in properties)
    {
        dictionary.Add(p.Name,p.GetValue(model));
    }

    // Prints: KeyWords,Categories
    Console.WriteLine(string.Join(",",dictionary.Keys));
    // Prints: overengineering,1|2|3
    Console.WriteLine(string.Join(",dictionary.Values));
}

该死的,这可能是我在SO所给出的最长的答案.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读