20

Why can't I do like this?

[Required(ErrorMessage = "*")]
[RegularExpression("^[a-zA-Z0-9_]*$", ErrorMessage = Resources.RegistrationModel.UsernameError)]
public string Username { get; set; }

What is the error message telling me?

An attribute argument must be a constant expression , typeof expression or array creation expression of an attribute parameter type.

DaveRandom
  • 87,921
  • 11
  • 154
  • 174
Johan Alkstål
  • 5,225
  • 9
  • 36
  • 48

6 Answers6

52

When you are using the ErrorMessage property only constant strings or string literal can be assigned to it.

Use the ErrorMessageResourceType and ErrorMessageResourceName instead to specity your resources.

[RegularExpression(
    "^[a-zA-Z0-9_]*$", 
    ErrorMessageResourceType=typeof(Resources.RegistrationModel),
    ErrorMessageResourceName= "UsernameError"
)]

Note that the resources must be public (can be set in the resource editor).

Setting resource access to public

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
AxelEckenberger
  • 16,628
  • 3
  • 48
  • 70
  • 1
    What if the resource is in App_GlobalResources? You can't change the Access Modifier for globalresources. Would you be forced to move those resources elsewhere in order for them to work with DataAnnotations? – Johan Alkstål Apr 22 '10 at 08:55
  • @JohanVauhkonen you can change the Build Action to `Embedded Resource` and Custom Tool to `PublicResXFileCodeGenerator` – Bart Calixto Sep 19 '13 at 23:50
  • This may work, but according to the ASP.NET CORE documentation here: https://docs.asp.net/en/latest/fundamentals/localization.html#dataannotations-localization, we should be able to localize these DataAnnotation error messages without specifying resource name and type. Whatever I try, however, I do not mange to get this working. Can someone share some experience on that? – Vladislav Sep 01 '16 at 12:53
3

Please see this link: http://code.msdn.microsoft.com/Getting-Started-WCF-RIA-1469cbe2/sourcecode?fileId=19242&pathId=774666288 (link broken, but left for attribution purposes)

public sealed partial class RegistrationData 
{ 
    [Key] 
    [Required(ErrorMessageResourceName = "ValidationErrorRequiredField", ErrorMessageResourceType = typeof(ErrorResources))] 
    [Display(Order = 0, Name = "UserNameLabel", ResourceType = typeof(RegistrationDataResources))] 
    [RegularExpression("^[a-zA-Z0-9_]*$", ErrorMessageResourceName = "ValidationErrorInvalidUserName", ErrorMessageResourceType = typeof(ErrorResources))] 
    [StringLength(255, MinimumLength = 4, ErrorMessageResourceName = "ValidationErrorBadUserNameLength", ErrorMessageResourceType = typeof(ErrorResources))] 
    public string UserName { get; set; } 
Andrew Barber
  • 39,603
  • 20
  • 94
  • 123
Feng
  • 83
  • 6
  • +1 for showing a complete list of attributes that use this pattern. In particular, it's easy to miss that Display is different from the rest. "Name" is the name in the resource file... – Elton Jun 19 '15 at 15:41
1

Try FluentModelMetaDataProvider.

Managed to use resources for error messages in strongly typed fashion.

Looks like this:

using System.Web.Mvc.Extensibility;

namespace UI.Model
{
    public class StoreInputMetadata : ModelMetadataConfigurationBase<StoreInput>
    {
        public StoreInputMetadata()
        {
            Configure(m => m.Id)
                .Hide();
            Configure(model => model.Name)
                .Required(Resources.Whatever.StoreIsRequired)
                .MaximumLength(64, Resources.Whatever.StoreNameLengthSomething);
        }
    }
}

What is the error message telling me?

An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type.

It's already self explanatory. C# isn't dynamic language like Ruby where You can write classes that inherits random base class at runtime. :)

Here's what Skeet says about this.

Community
  • 1
  • 1
Arnis Lapsa
  • 45,880
  • 29
  • 115
  • 195
0

It means that you cannot determine the value of the argument you are passing into the attribute at runtime, it must be at compile time so the value is embedded into the assembly.

The error message value needs to be a constant expression.

For information, attribute arguments can only be of types bool, byte, char, short, int, long, float, double, string, System.Type, and enums.

David Neale
  • 16,498
  • 6
  • 59
  • 85
0

You should instead look at the ErrorMessageResourceName and ErrorMessageResourceType properties of this attribute. They do allow the error message to be pulled from a resource.

Basheer AL-MOMANI
  • 14,473
  • 9
  • 96
  • 92
Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
0

We can now use nameof for strongly typed error messages:

[RegularExpression("^[a-zA-Z0-9_]*$", 
  ErrorMessageResourceType=typeof(Resources.RegistrationModel),
  ErrorMessageResourceName=nameof(Resources.RegistrationModel.UsernameError)
)]
drewmagoo
  • 15
  • 2
  • 5