In MVC 3 non hai fortuna perché i valori del percorso sono memorizzati in un RouteValueDictionary
che come suggerisce il nome utilizza uno Dictionary
internamente che non consente di avere più valori associati a una singola chiave. I valori del percorso dovrebbero probabilmente essere memorizzati in un NameValueCollection
per supportare lo stesso comportamento della stringa di query.
Tuttavia, se si può imporre alcuni vincoli sui nomi categorie e siete in grado di supportare una stringa di query nel formato:
http://www.test.com/search/index?keywords=bla&categories=Cat1|Cat2
allora si potrebbe teoricamente collegarlo Html.ActionLink
dal MVC utilizza TypeDescriptor
che a sua volta è estensibile in fase di runtime. Il seguente codice è presentato per dimostrare che è possibile, ma non lo consiglierei di essere utilizzato, almeno senza ulteriori refactoring.
Detto questo, si avrebbe bisogno di iniziare associando una descrizione tipo personalizzato fornitore:
[TypeDescriptionProvider(typeof(SearchModelTypeDescriptionProvider))]
public class SearchModel
{
public string KeyWords { get; set; }
public IList<string> Categories { get; set; }
}
L'implementazione per il provider e il descrittore personalizzato che sostituisce il descrittore di proprietà per la Categories
immobile:
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);
}
}
Quindi avremmo bisogno del descrittore di proprietà personalizzato per poter restituire un valore personalizzato in GetValue
che viene chiamato internamente da 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();
}
}
E infine per dimostrare che funziona un'applicazione di esempio che imita la creazione valori percorso 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));
}
Accidenti, questa è probabilmente la risposta più lunga che io abbia mai dato qui a SO.
Sembra un duplicato: http://stackoverflow.com/q/1752721/25727. Vedere la prima risposta per una soluzione con un HtmlHelper personalizzato. – Jan