[Fixes #2817] Support client side validation for all numeric types
This commit is contained in:
parent
7aa5967cd4
commit
4295a57504
|
|
@ -2,11 +2,12 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.Framework.Internal;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
{
|
{
|
||||||
public interface IClientModelValidator
|
public interface IClientModelValidator
|
||||||
{
|
{
|
||||||
IEnumerable<ModelClientValidationRule> GetClientValidationRules(ClientModelValidationContext context);
|
IEnumerable<ModelClientValidationRule> GetClientValidationRules([NotNull] ClientModelValidationContext context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.Framework.Internal;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -13,6 +15,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
/// by updating <see cref="ClientValidatorProviderContext.Validators"/>.
|
/// by updating <see cref="ClientValidatorProviderContext.Validators"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context">The <see cref="ClientModelValidationContext"/> associated with this call.</param>
|
/// <param name="context">The <see cref="ClientModelValidationContext"/> associated with this call.</param>
|
||||||
void GetValidators(ClientValidatorProviderContext context);
|
void GetValidators([NotNull] ClientValidatorProviderContext context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
// 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 Microsoft.Framework.Internal;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This is a <see cref="ModelClientValidationRule"/> for numeric values.
|
||||||
|
/// </summary>
|
||||||
|
public class ModelClientValidationNumericRule : ModelClientValidationRule
|
||||||
|
{
|
||||||
|
private const string NumericValidationType = "number";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an instance of <see cref="ModelClientValidationNumericRule"/>
|
||||||
|
/// with the given <paramref name="errorMessage"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="errorMessage">The error message to be displayed.</param>
|
||||||
|
public ModelClientValidationNumericRule([NotNull] string errorMessage)
|
||||||
|
: base(NumericValidationType, errorMessage)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
// 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.Collections.Generic;
|
||||||
|
using Microsoft.AspNet.Mvc.DataAnnotations;
|
||||||
|
using Microsoft.Framework.Internal;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An implementation of <see cref="IClientModelValidator"/> that provides the rule for validating
|
||||||
|
/// numeric types.
|
||||||
|
/// </summary>
|
||||||
|
public class NumericClientModelValidator : IClientModelValidator
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ClientModelValidationContext context)
|
||||||
|
{
|
||||||
|
return new[] { new ModelClientValidationNumericRule(GetErrorMessage(context.ModelMetadata)) };
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetErrorMessage([NotNull] ModelMetadata modelMetadata)
|
||||||
|
{
|
||||||
|
return Resources.FormatNumericClientModelValidator_FieldMustBeNumber(modelMetadata.GetDisplayName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An implementation of <see cref="IClientModelValidatorProvider"/> which provides client validators
|
||||||
|
/// for specific numeric types.
|
||||||
|
/// </summary>
|
||||||
|
public class NumericClientModelValidatorProvider : IClientModelValidatorProvider
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void GetValidators(ClientValidatorProviderContext context)
|
||||||
|
{
|
||||||
|
var type = context.ModelMetadata.ModelType;
|
||||||
|
var typeToValidate = Nullable.GetUnderlyingType(type) ?? type;
|
||||||
|
|
||||||
|
// Check only the numeric types for which we set type='text'.
|
||||||
|
if (typeToValidate == typeof(float) ||
|
||||||
|
typeToValidate == typeof(double) ||
|
||||||
|
typeToValidate == typeof(decimal))
|
||||||
|
{
|
||||||
|
context.Validators.Add(new NumericClientModelValidator());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -42,6 +42,22 @@ namespace Microsoft.AspNet.Mvc.DataAnnotations
|
||||||
return GetString("ArgumentCannotBeNullOrEmpty");
|
return GetString("ArgumentCannotBeNullOrEmpty");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The field {0} must be a number.
|
||||||
|
/// </summary>
|
||||||
|
internal static string NumericClientModelValidator_FieldMustBeNumber
|
||||||
|
{
|
||||||
|
get { return GetString("NumericClientModelValidator_FieldMustBeNumber"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The field {0} must be a number.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatNumericClientModelValidator_FieldMustBeNumber(object p0)
|
||||||
|
{
|
||||||
|
return string.Format(CultureInfo.CurrentCulture, GetString("NumericClientModelValidator_FieldMustBeNumber"), p0);
|
||||||
|
}
|
||||||
|
|
||||||
private static string GetString(string name, params string[] formatterNames)
|
private static string GetString(string name, params string[] formatterNames)
|
||||||
{
|
{
|
||||||
var value = _resourceManager.GetString(name);
|
var value = _resourceManager.GetString(name);
|
||||||
|
|
|
||||||
|
|
@ -123,4 +123,7 @@
|
||||||
<data name="ArgumentCannotBeNullOrEmpty" xml:space="preserve">
|
<data name="ArgumentCannotBeNullOrEmpty" xml:space="preserve">
|
||||||
<value>Value cannot be null or empty.</value>
|
<value>Value cannot be null or empty.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="NumericClientModelValidator_FieldMustBeNumber" xml:space="preserve">
|
||||||
|
<value>The field {0} must be a number.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -25,6 +25,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
// Set up client validators
|
// Set up client validators
|
||||||
options.ClientModelValidatorProviders.Add(new DefaultClientModelValidatorProvider());
|
options.ClientModelValidatorProviders.Add(new DefaultClientModelValidatorProvider());
|
||||||
options.ClientModelValidatorProviders.Add(new DataAnnotationsClientModelValidatorProvider());
|
options.ClientModelValidatorProviders.Add(new DataAnnotationsClientModelValidatorProvider());
|
||||||
|
options.ClientModelValidatorProviders.Add(new NumericClientModelValidatorProvider());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
// 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 Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
|
{
|
||||||
|
public class DataTypeClientModelValidatorProviderTest
|
||||||
|
{
|
||||||
|
private readonly IModelMetadataProvider _metadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(typeof(float))]
|
||||||
|
[InlineData(typeof(double))]
|
||||||
|
[InlineData(typeof(decimal))]
|
||||||
|
[InlineData(typeof(float?))]
|
||||||
|
[InlineData(typeof(double?))]
|
||||||
|
[InlineData(typeof(decimal?))]
|
||||||
|
public void GetValidators_GetsNumericValidator_ForNumericType(Type modelType)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var provider = new NumericClientModelValidatorProvider();
|
||||||
|
var metadata = _metadataProvider.GetMetadataForType(modelType);
|
||||||
|
|
||||||
|
var providerContext = new ClientValidatorProviderContext(metadata);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
provider.GetValidators(providerContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var validator = Assert.Single(providerContext.Validators);
|
||||||
|
Assert.IsType<NumericClientModelValidator>(validator);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(typeof(int))]
|
||||||
|
[InlineData(typeof(short))]
|
||||||
|
[InlineData(typeof(byte))]
|
||||||
|
[InlineData(typeof(uint?))]
|
||||||
|
[InlineData(typeof(long?))]
|
||||||
|
[InlineData(typeof(string))]
|
||||||
|
[InlineData(typeof(DateTime))]
|
||||||
|
public void GetValidators_DoesNotGetsNumericValidator_ForUnsupportedTypes(Type modelType)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var provider = new NumericClientModelValidatorProvider();
|
||||||
|
var metadata = _metadataProvider.GetMetadataForType(modelType);
|
||||||
|
|
||||||
|
var providerContext = new ClientValidatorProviderContext(metadata);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
provider.GetValidators(providerContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Empty(providerContext.Validators);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
// 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.ComponentModel.DataAnnotations;
|
||||||
|
using Microsoft.AspNet.Testing;
|
||||||
|
using Microsoft.Framework.DependencyInjection;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
|
{
|
||||||
|
public class NumericClientModelValidatorTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
[ReplaceCulture]
|
||||||
|
public void ClientRulesWithCorrectValidationTypeAndErrorMessage()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var provider = TestModelMetadataProvider.CreateDefaultProvider();
|
||||||
|
var metadata = provider.GetMetadataForProperty(typeof(TypeWithNumericProperty), "Id");
|
||||||
|
var adapter = new NumericClientModelValidator();
|
||||||
|
var serviceCollection = new ServiceCollection();
|
||||||
|
var requestServices = serviceCollection.BuildServiceProvider();
|
||||||
|
var context = new ClientModelValidationContext(metadata, provider, requestServices);
|
||||||
|
var expectedMessage = "The field DisplayId must be a number.";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var rules = adapter.GetClientValidationRules(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var rule = Assert.Single(rules);
|
||||||
|
Assert.Equal("number", rule.ValidationType);
|
||||||
|
Assert.Equal(expectedMessage, rule.ErrorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TypeWithNumericProperty
|
||||||
|
{
|
||||||
|
[Display(Name = "DisplayId")]
|
||||||
|
public float Id { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -114,9 +114,10 @@ namespace Microsoft.AspNet.Mvc
|
||||||
var options = GetOptions<MvcViewOptions>(AddDnxServices);
|
var options = GetOptions<MvcViewOptions>(AddDnxServices);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(2, options.ClientModelValidatorProviders.Count);
|
Assert.Equal(3, options.ClientModelValidatorProviders.Count);
|
||||||
Assert.IsType<DefaultClientModelValidatorProvider>(options.ClientModelValidatorProviders[0]);
|
Assert.IsType<DefaultClientModelValidatorProvider>(options.ClientModelValidatorProviders[0]);
|
||||||
Assert.IsType<DataAnnotationsClientModelValidatorProvider>(options.ClientModelValidatorProviders[1]);
|
Assert.IsType<DataAnnotationsClientModelValidatorProvider>(options.ClientModelValidatorProviders[1]);
|
||||||
|
Assert.IsType<NumericClientModelValidatorProvider>(options.ClientModelValidatorProviders[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue