lom*_*axx 6 asp.net-mvc asp.net-mvc-routing
我正在尝试使用以下viewmodel生成Html.ActionLink:
public class SearchModel
{
public string KeyWords {get;set;}
public IList<string> Categories {get;set;}
}
Run Code Online (Sandbox Code Playgroud)
要生成我的链接,我使用以下调用:
@Html.ActionLink("Index", "Search", Model)
Run Code Online (Sandbox Code Playgroud)
其中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 中,您只是运气不好,因为路由值存储在 a 中RouteValueDictionary,顾名思义,它Dictionary在内部使用 a ,这使得不可能将多个值关联到单个键。路由值可能应该存储在 a 中NameValueCollection以支持与查询字符串相同的行为。
但是,如果您可以对类别名称施加一些限制,并且您能够支持以下格式的查询字符串:
http://www.test.com/search/index?keywords=bla&categories=Cat1|Cat2
Run Code Online (Sandbox Code Playgroud)
那么理论上你可以将其插入Html.ActionLink,因为 MVC 使用TypeDescriptor它在运行时又是可扩展的。下面的代码是为了证明它是可能的,但我不建议使用它,至少在不进一步重构的情况下。
话虽如此,您需要首先关联自定义类型描述提供程序:
[TypeDescriptionProvider(typeof(SearchModelTypeDescriptionProvider))]
public class SearchModel
{
public string KeyWords { get; set; }
public IList<string> Categories { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
提供者和覆盖属性描述符的自定义描述符的实现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);
}
}
Run Code Online (Sandbox Code Playgroud)
然后我们需要自定义属性描述符能够返回一个自定义值,其中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();
}
}
Run Code Online (Sandbox Code Playgroud)
最后,为了证明它可以运行一个模拟 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));
}
Run Code Online (Sandbox Code Playgroud)
该死的,这可能是我在这里给出的最长的答案。
| 归档时间: |
|
| 查看次数: |
917 次 |
| 最近记录: |