Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Asp.net mvc 在传递到Html.ActionLink时序列化模型上的IList属性_Asp.net Mvc_Asp.net Mvc Routing - Fatal编程技术网

Asp.net mvc 在传递到Html.ActionLink时序列化模型上的IList属性

Asp.net mvc 在传递到Html.ActionLink时序列化模型上的IList属性,asp.net-mvc,asp.net-mvc-routing,Asp.net Mvc,Asp.net Mvc Routing,我正在尝试使用以下viewmodel生成Html.ActionLink: public class SearchModel { public string KeyWords {get;set;} public IList<string> Categories {get;set;} } 其中Model是SearchModel的一个实例 生成的链接如下所示: 因为它显然只对每个属性调用ToString方法 我希望看到的是: 我有没有办法通过使用Html.Action

我正在尝试使用以下viewmodel生成Html.ActionLink:

public class SearchModel
{
    public string KeyWords {get;set;}
    public IList<string> Categories {get;set;}
}
其中Model是SearchModel的一个实例

生成的链接如下所示:

因为它显然只对每个属性调用ToString方法

我希望看到的是:


我有没有办法通过使用
Html.ActionLink

和linq一起实现这一点?当然

string.Join("", Model.Categories.Select(c=>"&categories="+c))

在MVC 3中,您只是运气不佳,因为路由值存储在
RouteValueDictionary
中,顾名思义,它在内部使用
字典,这使得不可能将多个值与单个键关联。路由值可能应该存储在
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; }
}
然后,我们需要自定义属性描述符能够在
GetValue
中返回一个自定义值,该值由MVC内部调用:

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();
    }
}
类ListPropertyDescriptor:PropertyDescriptor
{
公共ListPropertyDescriptor(字符串名称)
:base(名称,新属性[]{}{}
公共覆盖布尔CanResetValue(对象组件)
{
返回false;
}
公共重写类型ComponentType
{
获取{抛出新的NotImplementedException();}
}
公共覆盖对象GetValue(对象组件)
{
var property=component.GetType().GetProperty(this.Name);
var list=(IList)property.GetValue(component,null);
返回字符串。Join(“|”,list);
}
公共重写bool IsReadOnly{get{return false;}}
公共覆盖类型PropertyType
{
获取{抛出新的NotImplementedException();}
}
公共重写无效重置值(对象组件){}
公共重写void SetValue(对象组件,对象值){}
公共重写bool ShouldSerializeValue(对象组件)
{
抛出新的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));
}
static void Main(字符串[]args)
{
var模型=新搜索模型{KeyWords=“overengineering”};
model.Categories=新列表{“1”、“2”、“3”};
var properties=TypeDescriptor.GetProperties(模型);
var dictionary=newdictionary();
foreach(属性中的PropertyDescriptor p)
{
Add(p.Name,p.GetValue(model));
}
//印刷品:关键词、类别
WriteLine(string.Join(“,”,dictionary.Keys));
//版画:过度设计,1 | 2 | 3
WriteLine(string.Join(“,”,dictionary.Values));
}

该死,这可能是我在这里给出的最长答案。

看起来像是重复的:。请参阅使用自定义HtmlHelper的解决方案的第一个答案。如何将其插入到Html.ActionLink调用中?嗯,我不知道,我会用手写的方式感谢您的回答。它非常接近于让它吐出正确的值,只是如果使用|作为分隔符,那么在返回的过程中必须使用自定义模型绑定器,所以我更改了版本,使分隔符为string.Format(&{0},property.Name)。。。工作起来很有魅力!“过度工程”这个词在这里确实有它的位置:)这是一个可笑的复杂的解决方案,可以用linq来解决:)但是很好的概念证明。@rouen这不是过度工程,实际上linq也不能解决。字符串的连接是,但这不是全部问题,它只是问题的一部分。另一部分是让它在路由模型中作为一等公民使用。这就是乔试图证明的
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();
    }
}
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));
}