locked
C# data annotation, can't extend a specific attribute - what are the possibilities? RRS feed

  • Question

  • User-2076968464 posted

    I'm working on a legacy application build with ASP.NET Dynamic Data. The models, as per usual, are all read-only and one can set the display name or description through attributes.

    This worked well, however, now I'm in a situation where I need to query two different sources (resource file and some other source) for display name.

    The code before was clean, because we only queried the resources:

    [Display(ResourceType = typeof(Resources.m_Res), Name = "M_RES_MIMETYPE_ID", Description = "M_RES_MIMETYPE_ID_DESCR")]

    This was totally fine and it worked as intended. However, now I have to get the display name and description firstly from some other file and if everything else fails, I have to fallback to resources.

    I had to create two different custom attributes, something in this manner:

            public class MGADisplayName : DisplayNameAttribute
            {
                  private readonly string propertyName;
                  public string Name { get; set; }
                  public Type TableName { get; set; }
                  public Type ResourceType { get; set; }
    
                  public MGADisplayName([CallerMemberName] string PropertyName = null)
                  {
                      propertyName = PropertyName;
                  }
    
                  public override string DisplayName
                  {
                      get
                      {
                          var key = (TableName.Name + ":" + (propertyName ?? Name)).ToLower();
                          if (/* SOME QUERYING */)
                          {
                              return QUERY[key];
                          }
                          else
                          {
                              string property = Resources.m_Res.ResourceManager.GetString(Name);
                              if (property != null)
                              {
                                  return property;
                              }
                              else
                              {
                                  return Name;
                              }
    
                          }
                      }
                  }
            }

    This kind of works and I guess it's OK for the time being, but the next issue is around the corner: I'll need to do with Display.GroupName the same.

    Now, as far as I know, there is no GroupNameAttribute to extend, so I'm kind of in the dark here.

    I wish I could extend the DisplayAttribute, it would be EXACTLY what I need, but the class is sealed, so that's a dead end.

    I wish I could change the model on the fly and provide DisplayName and Description through setters, but the model has only getters, so that's another dead end.

    I'm running slowly out of options here. What else can be done here?

    Tuesday, April 28, 2020 11:44 AM

All replies

  • User753101303 posted

    Hi,

    Have you tried to see if you could customize m_Rest instead?

    Tuesday, April 28, 2020 3:57 PM
  • User-2076968464 posted

    AFAIK resources is just a plain key-value file. I need some logic in that. If it would be possible to pass some kind of method or something that can take control of how the Display attribute handles this, that would be a life-saver. I need to somehow gain access to database...

    Tuesday, April 28, 2020 4:48 PM
  • User753101303 posted

    If you look at the type you are providing to the Display attribute you should find this is already some C# code exposing resources data. Also as for other features ASP.NET uses a "provider" model that allows to expose resources regardless of where they are really coming from, resource files being just the default option.

    It would require a closer look but IMO it should be possible to:
    - replace this resource type with your own type (if I remember just a static class with static properties). It could return hardcoded string. This is just to see if it works technically speaking

    If confirmed you could expand on that and plug your own logic behind those properties. If you want later to go further and depending on the underlying code generated for this resource file, it might be even possible to write a "custom resource provider" that would expose db strings as if they were coming from a resouce file.

    Not sure but even maybe plugin at the ASP.NET level and then having this done for you with no other code change than adding and registering this custom provider.

    Try perhaps to check the type is just a static class with static properties. I'll try to see if it can be pushed further when I'll have some free time.

    Wednesday, April 29, 2020 11:36 AM
  • User-2076968464 posted

    Thank you so much for your reply!

    Yes, I managed to create a class with static properties and take control of what's going on. Here's a quick example, some things were intentionally obfuscated:

    public class CustomResources
    {
        private static string tableName = typeof(m_SOME_CLASS_NAME).Name;
        private static ResourceManager resources = new ResourceManager(typeof(Resources.m_SOME_CLASS_NAME_RESOURCES));
        private static string GetValue(string propertyName, [CallerMemberName] string name = null)
        {
            var key = (tableName + ":" + propertyName).ToLower();
            if (SessionKeys.DisplayColumns.ContainsKey(key))
            {
                return SessionKeys.DisplayColumns[key].DisplayNameColumn;
            }
            else
            {
                var property = resources.GetString(name);
                if (property != null)
                {
                    return property;
                }
                else
                {
                    return propertyName;
                }
    
            }
        }
    
        public static string M_N_FIELD
        {
            get
            {
                return GetValue("N_FIELD");
            }
        }
    
        public static string M_N_FIELD_DESC
        {
            get
            {
                return GetValue("N_FIELD");
            }
        }
    }

    This is how it's called:

    [Display(ResourceType = typeof(CustomResources), Name = "M_N_FIELD", Description = "M_N_FIELD_DESC")]
                [ColumnOrder(13)]
                [FilterUIHint("WhereDropdownList")]
                public object N_FIELD{ get; set; }

    While this works, I'm now faced with 50 classes that have a round 20+ properties. Naturally. writing such custom resource file would be incredibly time consuming.

    What would you suggests?

    Thanks a ton for your help.

    Wednesday, April 29, 2020 12:45 PM