1

Closed

CompareAttribute does not use custom error messages

description

Scenario:
User likes to customise/localise the error message for the Data Annotations CompareAttribute in a view model.

Issue:
When the Data Annotations Compare attribute (System.ComponentModel.DataAnnotations.CompareAttribute) is used with custom error messages, the custom error messages are never shown, instead the default error message is always shown.

Example model:
private class ExampleModelWithCustomErrorMessage
{
    [Compare("OtherProperty", ErrorMessage = "Custom error message")]
    public string MyProperty { get; set; }

    public string OtherProperty { get; set; }
}
same issue with error message from a resource, i.e.
private class ExampleModelWithCustomErrorMessageFromResource
{
    [Compare("OtherProperty", ErrorMessageResourceType = typeof(Resource.Resource), ErrorMessageResourceName = "ResourceKey"))]
    public string MyProperty { get; set; }

    public string OtherProperty { get; set; }
}
The above examples will both print the default error message 'MyProperty' does not match 'OtherProperty'.

Reason:
CompareAttributeWrapper in CompareAttributeAdapter does not copy over the custom error message properties when creating a new, wrapped CompareAttribute.

New unit test in CompareAttributeAdapterTest.cs:
[Fact]
public void ClientRulesWithCompareAttribute_ErrorMessageCanBeCustomised()
{
    // Arrange
    const string expectedErrorMessage = "Computer says no";
    var metadata = ModelMetadataProviders.Current.GetMetadataForProperty(() => null, typeof(PropertyNameModel), "MyProperty");
    var context = new ControllerContext();
    var attribute = new System.ComponentModel.DataAnnotations.CompareAttribute("OtherProperty")
        {
            ErrorMessage = expectedErrorMessage
        };

    var adapter = new CompareAttributeAdapter(metadata, context, attribute);

    // Act
    var rules = adapter.GetClientValidationRules()
        .OrderBy(r => r.ValidationType)
        .ToArray();

    // Assert
    ModelClientValidationRule rule = Assert.Single(rules);
    Assert.Equal(expectedErrorMessage, rule.ErrorMessage);
}
Here is also an attempt at fixing the issue (CompareAttributeAdapter.cs:37)
public CompareAttributeWrapper(DataAnnotationsCompareAttribute attribute, ModelMetadata metadata)
    : base(attribute.OtherProperty)
{
    ErrorMessage = attribute.ErrorMessage;
    ErrorMessageResourceType = attribute.ErrorMessageResourceType;
    ErrorMessageResourceName = attribute.ErrorMessageResourceName;

    _otherPropertyDisplayName = attribute.OtherPropertyDisplayName;
    if (_otherPropertyDisplayName == null && metadata.ContainerType != null)
    {
        _otherPropertyDisplayName = ModelMetadataProviders.Current.GetMetadataForProperty(() => metadata.Model, metadata.ContainerType, attribute.OtherProperty).GetDisplayName();
    }
}

file attachments

Closed Nov 20, 2013 at 10:29 PM by kirthik

comments

henkli wrote Nov 7, 2013 at 7:30 AM

Unit test for CompareAttributeAdapter and attempted fix.

dougbu wrote Nov 20, 2013 at 5:38 AM

Fixed in commit 5003c3a8eff3.

davidmatson wrote Jan 24 at 6:38 PM

Fixed in changeset 5003c3a8eff3be63a63cccdec31dd24aa2ebe1a1