Trong MVC 3, bạn không may mắn vì các giá trị tuyến đường được lưu trữ trong một RouteValueDictionary
như tên gọi ngụ ý sử dụng Dictionary
nội bộ khiến không thể có nhiều giá trị được liên kết với một khóa duy nhất. Giá trị tuyến đường có thể được lưu trữ trong một NameValueCollection
để hỗ trợ hành vi tương tự như chuỗi truy vấn.
Tuy nhiên, nếu bạn có thể áp đặt một số hạn chế về tên loại và bạn có thể hỗ trợ một chuỗi truy vấn trong các định dạng:
http://www.test.com/search/index?keywords=bla&categories=Cat1|Cat2
sau đó bạn lý thuyết có thể cắm nó vào Html.ActionLink
từ MVC sử dụng TypeDescriptor
mà lần lượt có thể mở rộng khi chạy. Đoạn mã sau đây được trình bày để chứng minh nó có thể, nhưng tôi sẽ không khuyên bạn nên sử dụng nó, ít nhất là không cần tái cấu trúc thêm.
Có nói rằng, bạn sẽ cần phải bắt đầu bằng cách kết hợp một nhà cung cấp mô tả kiểu tùy chỉnh:
[TypeDescriptionProvider(typeof(SearchModelTypeDescriptionProvider))]
public class SearchModel
{
public string KeyWords { get; set; }
public IList<string> Categories { get; set; }
}
Việc thực hiện cho nhà cung cấp và các mô tả tùy chỉnh đó sẽ ghi đè các mô tả tài sản cho Categories
tài sản:
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);
}
}
Sau đó, chúng tôi sẽ cần bộ mô tả thuộc tính tùy chỉnh để có thể trả lại giá trị tùy chỉnh trong GetValue
được gọi nội bộ theo 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();
}
}
Và cuối cùng để chứng minh rằng nó hoạt động một ứng dụng mẫu bắt chước MVC giá trị con đường sáng tạo:
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));
}
Chết tiệt, đây có lẽ là câu trả lời dài nhất mà tôi từng đưa ra ở đây tại SO.
Có vẻ như một bản sao: http://stackoverflow.com/q/1752721/25727. Xem câu trả lời đầu tiên cho một giải pháp với một HtmlHelper tùy chỉnh. – Jan