8

I'm using System.ComponontModel.DataAnnotations to validate my model objects. How could I replace messages standard attributes (Required and StringLength) produce without providing ErrorMessage attribute to each of them or sub classing them?

0

3 Answers 3

8

Writing new post because I need more formatting than comments provide.

Look at ValidationAttribute - base class of validation attributes.

If validation error occured, error message will be created by method:

public virtual string FormatErrorMessage(string name)
{
    return string.Format(CultureInfo.CurrentCulture, this.ErrorMessageString, new object[] { name });
}

Next look at ErrorMessageString property:

protected string ErrorMessageString
{
    get
    {
        if (this._resourceModeAccessorIncomplete)
        {
            throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, DataAnnotationsResources.ValidationAttribute_NeedBothResourceTypeAndResourceName, new object[0]));
        }
        return this.ResourceAccessor();
    }
}

Property ResourceAccessor can be setted from:

ValidationAttribute..ctor(Func<String>)
ValidationAttribute.set_ErrorMessage(String) : Void
ValidationAttribute.SetResourceAccessorByPropertyLookup() : Void

First of it is exactly used by dervided classes to format messages, second - the case when we set error message trough ErrorMessage property, and third - when resource strings used. Depending on your situation, you may use ErrorMessageResourceName.

Elsewhere let's look at derived constructors, for our example, Range Attribute:

private RangeAttribute()
    : base((Func<string>) (() => DataAnnotationsResources.RangeAttribute_ValidationError))
{
}

Here RangeAttribute_ValidationError is loaded from resource:

internal static string RangeAttribute_ValidationError
{
    get
    {
        return ResourceManager.GetString("RangeAttribute_ValidationError", resourceCulture);
    }
}

So you can create resource file for different tan default culture and overwrite messages there, like this:

http://www.codeproject.com/KB/aspnet/SatelliteAssemblies.aspx

http://msdn.microsoft.com/en-us/library/aa645513(VS.71).aspx

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks a lot Veton. The last part you've mentioned I have totally missed.
I can't understand how should the resource files be named (and where placed) to override ResourceManager from DataAnnotations.dll.
7

You can use ErrorMessage property of base class ValidationAttribute for all DataAnnotations validators.

For example:

[Range(0, 100, ErrorMessage = "Value for {0} must be between {1} and {2}")]
public int id;

Maybe it'll help.

2 Comments

True. But is there a way to replace the default message at once?
@FitzchakYitzchaki Did you ever achieved that?
0

For ASP.NET Core validation, refer to this page, where it explains how to set it up using the service engine:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc()
        .AddDataAnnotationsLocalization(options => {
            options.DataAnnotationLocalizerProvider = (type, factory) =>
                factory.Create(typeof(SharedResource));
        });
}

Otherwise (WPF, WinForms or .NET Framework), you can use reflection to interfere with the DataAnnotations resources and replace them with your own, which can then be automatically culture-dependent on your app's current culture. Refer to this answer for more:

void InitializeDataAnnotationsCulture()
{
  var sr = 
    typeof(ValidationAttribute)
      .Assembly
      .DefinedTypes
      //ensure class name according to current .NET you're using
      .Single(t => t.FullName == "System.SR");

  var resourceManager = 
    sr
      .DeclaredFields
      //ensure field name
      .Single(f => f.IsStatic && f.Name == "s_resourceManager");

  resourceManager
    .SetValue(null, 
      DataAnnotationsResources.ResourceManager, /* The generated RESX class in my proj */
      BindingFlags.NonPublic | BindingFlags.Static, null, null);

  var injected = resourceManager.GetValue(null) == DataAnnotationsResources.ResourceManager;
  Debug.Assert(injected);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.