4

Voici mon exigence de développement,Retrieve le nom du modèle dans l'attribut nom d'affichage personnalisé

Mes valeurs d'étiquettes sont stockées dans la base de données, et je veux encore utiliser l'annotation de données de manière déclarative, est de rendre mon modèle plus lisible.

Et voici mon approche,

j'ai décidé d'écrire sur mesure DisplayNameAttribute, où la valeur par défaut fournie par mon modèle sera écrasé par la valeur récupérée à partir de la base de données.

Voici la propriété définie dans le modèle,

[CustomDisplay(Name: "First Name")] 
    [CustomRequired(ErrorMessage: "{0} is required")] 
    public String FirstName { get; set; } 

Voici la classe d'attribut de nom d'affichage personnalisé,

public class CustomDisplayAttribute : DisplayNameAttribute 
{ 
    private string _defaultName; 
    private string _displayName; 

    public CustomDisplayAttribute(string Name) 
    { 
     _defaultName = Name; 
    } 

    public override string DisplayName 
    { 
     get 
     { 
      if (String.IsNullOrEmpty(_displayName)) 
      { 
       _displayName = DAO.RetrieveValue(**ModelName**, _defaultName); 
      } 
      return _displayName; 
     } 
    } 
} 

Maintenant, vous pouvez voir dans le code ci-dessus, ModelName est quelque chose que je besoin, mais je n'ai pas !! Pendant le débogage, je creuse dans ModelMetadataProviders.Current et peut voir la disponibilité du modèle actuel en action. Mais, comme il fait partie de membres statiques non-publics, je suis incapable d'y accéder à travers mon code.

enter image description here

J'ai écrit la méthode ci-dessous pour récupérer le nom du modèle par la réflexion,

private static string GetModelName() 
{ 
    var modelName = String.Empty; 
    FieldInfo info = typeof(CachedAssociatedMetadataProvider<CachedDataAnnotationsModelMetadata>) 
         .GetField("_typeIds", BindingFlags.NonPublic | BindingFlags.Static); 
    var types = (ConcurrentDictionary<Type, string>)info.GetValue(null); 
    modelName = types.FirstOrDefault().Key.Name; 
    return modelName; 
} 

Mais le problème est, la collection types me fournit des entrées pour tous les modèles (visité au moins une fois par l'utilisateur). Et il n'y a pas d'indice à savoir, qui est actuellement en action !!

enter image description here

Répondre

0

à mon humble avis Attributs devrait pas être utilisé pour faire des appels de base de données. Les attributs doivent être utilisés pour ajouter des métadonnées aux classes/propriétés etc ...

Donc, si vous êtes prêt à changer votre code pour ressembler davantage à l'architecture Microsoft pour MVC, vous aurez votre attribut personnalisé et un ModelMetadataProvider personnalisé :

public class CustomDisplayAttribute : Attribute 
{ 
    public CustomDisplayAttribute(string name) 
    { 
     Name = name; 
    } 

    public string Name { get; private set; } 
} 

Puis une nouvelle ModelMetadataProvider:

public class DatabaseModelMetadataProvider : DataAnnotationsModelMetadataProvider 
{ 
    public DatabaseModelMetadataProvider() 
    { 
    } 

    protected override ModelMetadata CreateMetadata(
    IEnumerable<Attribute> attributes, 
    Type containerType, 
    Func<object> modelAccessor, 
    Type modelType, 
    string propertyName) 
    { 
    var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName); 

    var displayAttribute = containerType == null 
     ? null as CustomDisplayAttribute 
     : containerType.GetProperty(propertyName) 
      .GetCustomAttributes(false) 
      .OfType<CustomDisplayAttribute>() 
      .FirstOrDefault(); 
    if (displayAttribute != null) 
    { 
     var displayValue = DAO.RetrieveValue(containerType.ToString(), displayAttribute.Name) 

     metadata.DisplayName = displayValue; 
    } 
    return metadata; 
    } 
} 

public class MyViewModel 
{ 
    public MyPropertyType PropertyName { get; set; } 
} 
  • CONTAINERTYPE = MyViewModel
  • modelType = MyPropertyType
  • propertyName = NomPropriété

Alors inscrivez-vous au fournisseur (global.asax ou autre):

ModelMetadataProviders.Current = new LocalizedModelMetadataProvider(); 

vous pouvez également jeter un oeil au ModelMetadata il a quelques autres choses que vous pourriez vouloir changer dans le futur.