En réponse à michaelalm de réponse et demande - voici ce que j'ai fini par faire. J'ai laissé l'original de la réponse cochée principalement de courtoisie, car l'une des solutions proposées par Nathan aurait travaillé.
La sortie de cette est un remplacement pour l' DefaultModelBinder
classe qui vous pouvez vous inscrire à l'échelle mondiale (permettant ainsi à tous les types de modèle de profiter de l'aliasing) ou de manière sélective pour hériter des classeurs de modèles personnalisés.
Tout commence, de manière prévisible avec:
/// <summary>
/// Allows you to create aliases that can be used for model properties at
/// model binding time (i.e. when data comes in from a request).
///
/// The type needs to be using the DefaultModelBinderEx model binder in
/// order for this to work.
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
public class BindAliasAttribute : Attribute
{
public BindAliasAttribute(string alias)
{
//ommitted: parameter checking
Alias = alias;
}
public string Alias { get; private set; }
}
Et puis, nous avons cette classe:
internal sealed class AliasedPropertyDescriptor : PropertyDescriptor
{
public PropertyDescriptor Inner { get; private set; }
public AliasedPropertyDescriptor(string alias, PropertyDescriptor inner)
: base(alias, null)
{
Inner = inner;
}
public override bool CanResetValue(object component)
{
return Inner.CanResetValue(component);
}
public override Type ComponentType
{
get { return Inner.ComponentType; }
}
public override object GetValue(object component)
{
return Inner.GetValue(component);
}
public override bool IsReadOnly
{
get { return Inner.IsReadOnly; }
}
public override Type PropertyType
{
get { return Inner.PropertyType; }
}
public override void ResetValue(object component)
{
Inner.ResetValue(component);
}
public override void SetValue(object component, object value)
{
Inner.SetValue(component, value);
}
public override bool ShouldSerializeValue(object component)
{
return Inner.ShouldSerializeValue(component);
}
}
Cette procuration un " bon " PropertyDescriptor que l'on trouve normalement par l' DefaultModelBinder
mais présente en son nom comme pseudonyme.
Ensuite, nous avons le nouveau modèle de classeur de la classe:
public class DefaultModelBinderEx : DefaultModelBinder
{
protected override System.ComponentModel.PropertyDescriptorCollection
GetModelProperties(ControllerContext controllerContext,
ModelBindingContext bindingContext)
{
var toReturn = base.GetModelProperties(controllerContext, bindingContext);
List<PropertyDescriptor> additional = new List<PropertyDescriptor>();
//now look for any aliasable properties in here
foreach (var p in
this.GetTypeDescriptor(controllerContext, bindingContext)
.GetProperties().Cast<PropertyDescriptor>())
{
foreach (var attr in p.Attributes.OfType<BindAliasAttribute>())
{
additional.Add(new AliasedPropertyDescriptor(attr.Alias, p));
if (bindingContext.PropertyMetadata.ContainsKey(p.Name))
bindingContext.PropertyMetadata.Add(attr.Alias,
bindingContext.PropertyMetadata[p.Name]);
}
}
return new PropertyDescriptorCollection
(toReturn.Cast<PropertyDescriptor>().Concat(additional).ToArray());
}
}
Et puis techniquement, c'est tout là est à lui. Vous pouvez maintenant enregistrer ce DefaultModelBinderEx
classe que le défaut à l'aide de la solution posté la réponse dans cette SORTE: Changer le modèle de classeur par défaut dans asp.net MVC, ou vous pouvez l'utiliser comme base pour votre propre modèle de classeur.
Une fois que vous avez sélectionné votre modèle pour la façon dont vous voulez que le liant à coup de pied, il vous suffit de l'appliquer à un type de modèle comme suit:
public class TestModelType
{
[BindAlias("LPN")]
//and you can add multiple aliases
[BindAlias("L")]
//.. ad infinitum
public string LongPropertyName { get; set; }
}
La raison que j'ai choisi ce code était parce que je voulais quelque chose qui pourrait fonctionner avec un type personnalisé descripteurs ainsi que d'être capable de travailler avec n'importe quel type. Aussi, je voulais la valeur de fournisseur de système pour être utilisé encore dans la recherche de modèle de valeurs de propriété. J'ai donc changé les méta-données qui l' DefaultModelBinder
voit quand il commence de liaison. C'est un peu plus longue haleine approche - mais, conceptuellement, c'est de faire à la méta données de niveau exactement ce que vous voulez qu'il fasse.
Un potentiellement intéressant, et un peu ennuyeux, effet secondaire si l' ValueProvider
contient des valeurs pour plus d'un alias ou un alias et de la propriété en son nom. Dans ce cas, seul l'un de l'extrait valeurs seront utilisées. Difficile de penser à un moyen de les fusionner le tout dans un type de façon sécuritaire lorsque vous êtes juste à travailler avec object
s si. Ceci est similaire, bien que, pour fournir une valeur dans un formulaire post et la chaîne de requête - et je ne suis pas sûr exactement ce que MVC dans ce scénario - mais je ne pense pas qu'il est recommandé de pratiquer.
Un autre problème est, bien sûr, que vous ne devez pas créer un alias qui est égal à un autre alias, ou en effet le nom d'une propriété réelle.
J'aime appliquer mes classeurs de modèle, en général, à l'aide de l' CustomModelBinderAttribute
classe. Le seul problème avec ce peut être si vous avez besoin de tirer du type de modèle et de le modifier de liaison du comportement depuis l' CustomModelBinderAttribute
est héritée dans l'attribut de la recherche effectuée par MVC.
Dans mon cas, ce n'est pas grave, je suis l'élaboration d'un nouveau cadre de site et je suis capable de pousser la nouvelle extensibilité dans ma base de liants en utilisant d'autres mécanismes pour répondre à ces nouveaux types; mais ce ne sera pas le cas pour tout le monde.