aspnetcore/src/Microsoft.AspNet.Mvc.DataAn.../CompareAttributeAdapter.cs

92 lines
4.1 KiB
C#

// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using Microsoft.Framework.Localization;
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
{
public class CompareAttributeAdapter : DataAnnotationsClientModelValidator<CompareAttribute>
{
public CompareAttributeAdapter(CompareAttribute attribute, IStringLocalizer stringLocalizer)
: base(new CompareAttributeWrapper(attribute), stringLocalizer)
{
if (attribute == null)
{
throw new ArgumentNullException(nameof(attribute));
}
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules(
ClientModelValidationContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var errorMessage = ((CompareAttributeWrapper)Attribute).FormatErrorMessage(context);
var clientRule = new ModelClientValidationEqualToRule(errorMessage,
FormatPropertyForClientValidation(Attribute.OtherProperty));
return new[] { clientRule };
}
private static string FormatPropertyForClientValidation(string property)
{
return "*." + property;
}
private sealed class CompareAttributeWrapper : CompareAttribute
{
public CompareAttributeWrapper(CompareAttribute attribute)
: base(attribute.OtherProperty)
{
// Copy settable properties from wrapped attribute. Don't reset default message accessor (set as
// CompareAttribute constructor calls ValidationAttribute constructor) when all properties are null to
// preserve default error message. Reset the message accessor when just ErrorMessageResourceType is
// non-null to ensure correct InvalidOperationException.
if (!string.IsNullOrEmpty(attribute.ErrorMessage) ||
!string.IsNullOrEmpty(attribute.ErrorMessageResourceName) ||
attribute.ErrorMessageResourceType != null)
{
ErrorMessage = attribute.ErrorMessage;
ErrorMessageResourceName = attribute.ErrorMessageResourceName;
ErrorMessageResourceType = attribute.ErrorMessageResourceType;
}
}
public string FormatErrorMessage(ClientModelValidationContext context)
{
var displayName = context.ModelMetadata.GetDisplayName();
return string.Format(CultureInfo.CurrentCulture,
ErrorMessageString,
displayName,
GetOtherPropertyDisplayName(context));
}
private string GetOtherPropertyDisplayName(ClientModelValidationContext context)
{
// The System.ComponentModel.DataAnnotations.CompareAttribute doesn't populate the
// OtherPropertyDisplayName until after IsValid() is called. Therefore, by the time we get
// the error message for client validation, the display name is not populated and won't be used.
var metadata = context.ModelMetadata;
var otherPropertyDisplayName = OtherPropertyDisplayName;
if (otherPropertyDisplayName == null && metadata.ContainerType != null)
{
var otherProperty = context.MetadataProvider.GetMetadataForProperty(
metadata.ContainerType,
OtherProperty);
if (otherProperty != null)
{
return otherProperty.GetDisplayName();
}
}
return OtherProperty;
}
}
}
}