[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.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||
{
|
||||
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.
|
||||
// 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>
|
||||
|
|
@ -13,6 +15,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
/// by updating <see cref="ClientValidatorProviderContext.Validators"/>.
|
||||
/// </summary>
|
||||
/// <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");
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
|
|
|
|||
|
|
@ -123,4 +123,7 @@
|
|||
<data name="ArgumentCannotBeNullOrEmpty" xml:space="preserve">
|
||||
<value>Value cannot be null or empty.</value>
|
||||
</data>
|
||||
<data name="NumericClientModelValidator_FieldMustBeNumber" xml:space="preserve">
|
||||
<value>The field {0} must be a number.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -25,6 +25,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
// Set up client validators
|
||||
options.ClientModelValidatorProviders.Add(new DefaultClientModelValidatorProvider());
|
||||
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);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, options.ClientModelValidatorProviders.Count);
|
||||
Assert.Equal(3, options.ClientModelValidatorProviders.Count);
|
||||
Assert.IsType<DefaultClientModelValidatorProvider>(options.ClientModelValidatorProviders[0]);
|
||||
Assert.IsType<DataAnnotationsClientModelValidatorProvider>(options.ClientModelValidatorProviders[1]);
|
||||
Assert.IsType<NumericClientModelValidatorProvider>(options.ClientModelValidatorProviders[2]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
Loading…
Reference in New Issue