MetadataPropertyType RangeAttribute

I seem to be missing something on using MetadataPropertyType when i need to add an ErrorMessage Property and its value to an exported Range Attribute.

    nativeTypes.ExportAttribute<System.ComponentModel.DataAnnotations.RangeAttribute>(x =>
    {
        var metadata = nativeTypes.GetGenerator().ToMetadataAttribute(x);
        metadata.Name = x.GetType().FullName;
        if (metadata.Args == null)
            metadata.Args = new List<MetadataPropertyType>();
        var attr = (System.ComponentModel.DataAnnotations.RangeAttribute)x;
        if (!string.IsNullOrEmpty(attr.ErrorMessage))
        {
            metadata.Args.Add(new MetadataPropertyType { Name = nameof(System.ComponentModel.DataAnnotations.RangeAttribute.ErrorMessage), Value = attr.ErrorMessage, TypeNamespace = "System", Type = nameof(String)});
        }
        return metadata;
    });

The ErrorMessage property is not emitted.

It seems that if there are no ConstructorArgs the Args emit properly, as in the case of DisplayAttribute.

You can only define ConstructorArgs or Args on MetadataAttribute, not both.

So if I wanted a Range attribute that looked like this:

[System.ComponentModel.DataAnnotations.Range(0, int.MaxValue, ErrorMessage = "Item was not found")]

The code above emits

[System.ComponentModel.DataAnnotations.RangeAttribute(0, 2147483647)]

if i change it to

metadata.Args.Add(new MetadataPropertyType { Name = nameof(System.ComponentModel.DataAnnotations.RangeAttribute.ErrorMessage), Value = attr.ErrorMessage, TypeNamespace = "System", Type = nameof(String)});

I get

[System.ComponentModel.DataAnnotations.RangeAttribute(0, 2147483647, "Item was not found")]

which doesn’t have the PropertyName identifier for the ErrorMessage property.

What am i doing wrong?

You can’t have an attribute that looks like that because you can’t mix Constructor Args and Property Args, it has to be one or the other, i.e. if you specify any properties, you have to specify all of them.

But Range has no default constructor. I have tried Adding all properties into the Args list as well as the ConstructorArgs list. I have tried clearing the ConstructorArgs and adding them back with no Args, I have tried clearing ConstructorArgs and Adding all properties to the Args list. Is there anything else you could suggest?

So the args without properties are constructor args:

(0, int.MaxValue, 

Which it doesn’t support mixing with property args:

, ErrorMessage = "Item was not found"

As it doesn’t look like Range has properties for Min/Max you wont be able to include them all. You could carry the ErrorMessage in a different attribute, e.g:

[Meta("ErrorMessage", "The Error")]

Or you could use the Emit Custom code feature to emit the exact attribute you want, e.g:

[EmitCsharp("[Range(0, int.MaxValue, ErrorMessage = \"Item was not found\")]")]

Which builds on the PrePropertyFilter where you could emit it in a generic filter.

Sir you are awesome. The emit was just the ticket.

1 Like