Add localizers to validation attributes
This commit is contained in:
parent
49acfd562e
commit
0889b18f95
|
|
@ -5,13 +5,14 @@ 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)
|
||||
: base(new CompareAttributeWrapper(attribute))
|
||||
public CompareAttributeAdapter(CompareAttribute attribute, IStringLocalizer stringLocalizer)
|
||||
: base(new CompareAttributeWrapper(attribute), stringLocalizer)
|
||||
{
|
||||
if (attribute == null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.Framework.Localization;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||
{
|
||||
|
|
@ -14,13 +15,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
public abstract class DataAnnotationsClientModelValidator<TAttribute> : IClientModelValidator
|
||||
where TAttribute : ValidationAttribute
|
||||
{
|
||||
private readonly IStringLocalizer _stringLocalizer;
|
||||
/// <summary>
|
||||
/// Create a new instance of <see cref="DataAnnotationsClientModelValidator{TAttribute}"/>.
|
||||
/// </summary>
|
||||
/// <param name="attribute">The <typeparamref name="TAttribute"/> instance to validate.</param>
|
||||
public DataAnnotationsClientModelValidator(TAttribute attribute)
|
||||
/// <param name="stringLocalizer">The <see cref="IStringLocalizer"/>.</param>
|
||||
public DataAnnotationsClientModelValidator(TAttribute attribute, IStringLocalizer stringLocalizer)
|
||||
{
|
||||
Attribute = attribute;
|
||||
_stringLocalizer = stringLocalizer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -48,7 +52,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
throw new ArgumentNullException(nameof(modelMetadata));
|
||||
}
|
||||
|
||||
return Attribute.FormatErrorMessage(modelMetadata.GetDisplayName());
|
||||
var displayName = modelMetadata.GetDisplayName();
|
||||
if (_stringLocalizer != null &&
|
||||
!string.IsNullOrEmpty(Attribute.ErrorMessage) &&
|
||||
string.IsNullOrEmpty(Attribute.ErrorMessageResourceName) &&
|
||||
Attribute.ErrorMessageResourceType == null)
|
||||
{
|
||||
return _stringLocalizer[displayName];
|
||||
}
|
||||
|
||||
return Attribute.FormatErrorMessage(displayName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using Microsoft.Framework.Localization;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||
{
|
||||
|
|
@ -18,11 +20,27 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
public class DataAnnotationsClientModelValidatorProvider : IClientModelValidatorProvider
|
||||
{
|
||||
// A factory for validators based on ValidationAttribute.
|
||||
internal delegate IClientModelValidator
|
||||
DataAnnotationsClientModelValidationFactory(ValidationAttribute attribute);
|
||||
internal delegate IClientModelValidator DataAnnotationsClientModelValidationFactory(
|
||||
ValidationAttribute attribute,
|
||||
IStringLocalizer stringLocalizer);
|
||||
|
||||
private readonly Dictionary<Type, DataAnnotationsClientModelValidationFactory> _attributeFactories =
|
||||
BuildAttributeFactoriesDictionary();
|
||||
private readonly IOptions<MvcDataAnnotationsLocalizationOptions> _options;
|
||||
private readonly IStringLocalizerFactory _stringLocalizerFactory;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new instance of <see cref="DataAnnotationsClientModelValidatorProvider"/>.
|
||||
/// </summary>
|
||||
/// <param name="options">The <see cref="IOptions{MvcDataAnnotationsLocalizationOptions}"/>.</param>
|
||||
/// <param name="stringLocalizerFactory">The <see cref="IStringLocalizerFactory"/>.</param>
|
||||
public DataAnnotationsClientModelValidatorProvider(
|
||||
IOptions<MvcDataAnnotationsLocalizationOptions> options,
|
||||
IStringLocalizerFactory stringLocalizerFactory)
|
||||
{
|
||||
_options = options;
|
||||
_stringLocalizerFactory = stringLocalizerFactory;
|
||||
}
|
||||
|
||||
internal Dictionary<Type, DataAnnotationsClientModelValidationFactory> AttributeFactories
|
||||
{
|
||||
|
|
@ -36,6 +54,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
IStringLocalizer stringLocalizer = null;
|
||||
if (_options.Value.DataAnnotationLocalizerProvider != null && _stringLocalizerFactory != null)
|
||||
{
|
||||
// This will pass first non-null type (either containerType or modelType) to delegate.
|
||||
// Pass the root model type(container type) if it is non null, else pass the model type.
|
||||
stringLocalizer = _options.Value.DataAnnotationLocalizerProvider(
|
||||
context.ModelMetadata.ContainerType ?? context.ModelMetadata.ModelType,
|
||||
_stringLocalizerFactory);
|
||||
}
|
||||
|
||||
var hasRequiredAttribute = false;
|
||||
|
||||
|
|
@ -46,14 +73,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
DataAnnotationsClientModelValidationFactory factory;
|
||||
if (_attributeFactories.TryGetValue(attribute.GetType(), out factory))
|
||||
{
|
||||
context.Validators.Add(factory(attribute));
|
||||
context.Validators.Add(factory(attribute, stringLocalizer));
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasRequiredAttribute && context.ModelMetadata.IsRequired)
|
||||
{
|
||||
// Add a default '[Required]' validator for generating HTML if necessary.
|
||||
context.Validators.Add(new RequiredAttributeAdapter(new RequiredAttribute()));
|
||||
context.Validators.Add(new RequiredAttributeAdapter(new RequiredAttribute(), stringLocalizer));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -63,47 +90,73 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
{
|
||||
{
|
||||
typeof(RegularExpressionAttribute),
|
||||
(attribute) => new RegularExpressionAttributeAdapter((RegularExpressionAttribute)attribute)
|
||||
(attribute, stringLocalizer) => new RegularExpressionAttributeAdapter(
|
||||
(RegularExpressionAttribute)attribute,
|
||||
stringLocalizer)
|
||||
},
|
||||
{
|
||||
typeof(MaxLengthAttribute),
|
||||
(attribute) => new MaxLengthAttributeAdapter((MaxLengthAttribute)attribute)
|
||||
(attribute, stringLocalizer) => new MaxLengthAttributeAdapter(
|
||||
(MaxLengthAttribute)attribute,
|
||||
stringLocalizer)
|
||||
},
|
||||
{
|
||||
typeof(MinLengthAttribute),
|
||||
(attribute) => new MinLengthAttributeAdapter((MinLengthAttribute)attribute)
|
||||
(attribute, stringLocalizer) => new MinLengthAttributeAdapter(
|
||||
(MinLengthAttribute)attribute,
|
||||
stringLocalizer)
|
||||
},
|
||||
{
|
||||
typeof(CompareAttribute),
|
||||
(attribute) => new CompareAttributeAdapter((CompareAttribute)attribute)
|
||||
(attribute, stringLocalizer) => new CompareAttributeAdapter(
|
||||
(CompareAttribute)attribute,
|
||||
stringLocalizer)
|
||||
},
|
||||
{
|
||||
typeof(RequiredAttribute),
|
||||
(attribute) => new RequiredAttributeAdapter((RequiredAttribute)attribute)
|
||||
(attribute, stringLocalizer) => new RequiredAttributeAdapter(
|
||||
(RequiredAttribute)attribute,
|
||||
stringLocalizer)
|
||||
},
|
||||
{
|
||||
typeof(RangeAttribute),
|
||||
(attribute) => new RangeAttributeAdapter((RangeAttribute)attribute)
|
||||
(attribute, stringLocalizer) => new RangeAttributeAdapter(
|
||||
(RangeAttribute)attribute,
|
||||
stringLocalizer)
|
||||
},
|
||||
{
|
||||
typeof(StringLengthAttribute),
|
||||
(attribute) => new StringLengthAttributeAdapter((StringLengthAttribute)attribute)
|
||||
(attribute, stringLocalizer) => new StringLengthAttributeAdapter(
|
||||
(StringLengthAttribute)attribute,
|
||||
stringLocalizer)
|
||||
},
|
||||
{
|
||||
typeof(CreditCardAttribute),
|
||||
(attribute) => new DataTypeAttributeAdapter((DataTypeAttribute)attribute, "creditcard")
|
||||
(attribute, stringLocalizer) => new DataTypeAttributeAdapter(
|
||||
(DataTypeAttribute)attribute,
|
||||
"creditcard",
|
||||
stringLocalizer)
|
||||
},
|
||||
{
|
||||
typeof(EmailAddressAttribute),
|
||||
(attribute) => new DataTypeAttributeAdapter((DataTypeAttribute)attribute, "email")
|
||||
(attribute, stringLocalizer) => new DataTypeAttributeAdapter(
|
||||
(DataTypeAttribute)attribute,
|
||||
"email",
|
||||
stringLocalizer)
|
||||
},
|
||||
{
|
||||
typeof(PhoneAttribute),
|
||||
(attribute) => new DataTypeAttributeAdapter((DataTypeAttribute)attribute, "phone")
|
||||
(attribute, stringLocalizer) => new DataTypeAttributeAdapter(
|
||||
(DataTypeAttribute)attribute,
|
||||
"phone",
|
||||
stringLocalizer)
|
||||
},
|
||||
{
|
||||
typeof(UrlAttribute),
|
||||
(attribute) => new DataTypeAttributeAdapter((DataTypeAttribute)attribute, "url")
|
||||
(attribute, stringLocalizer) => new DataTypeAttributeAdapter(
|
||||
(DataTypeAttribute)attribute,
|
||||
"url",
|
||||
stringLocalizer)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,12 +5,15 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using Microsoft.Framework.Localization;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||
{
|
||||
public class DataAnnotationsModelValidator : IModelValidator
|
||||
{
|
||||
public DataAnnotationsModelValidator(ValidationAttribute attribute)
|
||||
private IStringLocalizer _stringLocalizer;
|
||||
|
||||
public DataAnnotationsModelValidator(ValidationAttribute attribute, IStringLocalizer stringLocalizer)
|
||||
{
|
||||
if (attribute == null)
|
||||
{
|
||||
|
|
@ -18,9 +21,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
}
|
||||
|
||||
Attribute = attribute;
|
||||
_stringLocalizer = stringLocalizer;
|
||||
}
|
||||
|
||||
public ValidationAttribute Attribute { get; private set; }
|
||||
public ValidationAttribute Attribute { get; }
|
||||
|
||||
public bool IsRequired
|
||||
{
|
||||
|
|
@ -59,7 +63,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
errorMemberName = null;
|
||||
}
|
||||
|
||||
var validationResult = new ModelValidationResult(errorMemberName, result.ErrorMessage);
|
||||
string errorMessage = null;
|
||||
if (_stringLocalizer != null &&
|
||||
!string.IsNullOrEmpty(Attribute.ErrorMessage) &&
|
||||
string.IsNullOrEmpty(Attribute.ErrorMessageResourceName) &&
|
||||
Attribute.ErrorMessageResourceType == null)
|
||||
{
|
||||
errorMessage = _stringLocalizer[Attribute.ErrorMessage];
|
||||
}
|
||||
|
||||
var validationResult = new ModelValidationResult(errorMemberName, errorMessage ?? result.ErrorMessage);
|
||||
return new ModelValidationResult[] { validationResult };
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@
|
|||
// 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.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.Framework.Localization;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||
{
|
||||
|
|
@ -16,11 +17,35 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
/// </summary>
|
||||
public class DataAnnotationsModelValidatorProvider : IModelValidatorProvider
|
||||
{
|
||||
private readonly IOptions<MvcDataAnnotationsLocalizationOptions> _options;
|
||||
private readonly IStringLocalizerFactory _stringLocalizerFactory;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new instance of <see cref="DataAnnotationsModelValidatorProvider"/>.
|
||||
/// </summary>
|
||||
/// <param name="options">The <see cref="IOptions{MvcDataAnnotationsLocalizationOptions}"/>.</param>
|
||||
/// <param name="stringLocalizerFactory">The <see cref="IStringLocalizerFactory"/>.</param>
|
||||
public DataAnnotationsModelValidatorProvider(
|
||||
IOptions<MvcDataAnnotationsLocalizationOptions> options,
|
||||
IStringLocalizerFactory stringLocalizerFactory)
|
||||
{
|
||||
_options = options;
|
||||
_stringLocalizerFactory = stringLocalizerFactory;
|
||||
}
|
||||
|
||||
public void GetValidators(ModelValidatorProviderContext context)
|
||||
{
|
||||
IStringLocalizer stringLocalizer = null;
|
||||
if (_options.Value.DataAnnotationLocalizerProvider != null && _stringLocalizerFactory != null)
|
||||
{
|
||||
stringLocalizer = _options.Value.DataAnnotationLocalizerProvider(
|
||||
context.ModelMetadata.ContainerType ?? context.ModelMetadata.ModelType,
|
||||
_stringLocalizerFactory);
|
||||
}
|
||||
|
||||
foreach (var attribute in context.ValidatorMetadata.OfType<ValidationAttribute>())
|
||||
{
|
||||
context.Validators.Add(new DataAnnotationsModelValidator(attribute));
|
||||
context.Validators.Add(new DataAnnotationsModelValidator(attribute, stringLocalizer));
|
||||
}
|
||||
|
||||
// Produce a validator if the type supports IValidatableObject
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.AspNet.Mvc.DataAnnotations;
|
||||
using Microsoft.Framework.Localization;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||
{
|
||||
|
|
@ -14,10 +15,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
/// </summary>
|
||||
public class DataTypeAttributeAdapter : DataAnnotationsClientModelValidator<DataTypeAttribute>
|
||||
{
|
||||
public DataTypeAttributeAdapter(
|
||||
DataTypeAttribute attribute,
|
||||
string ruleName)
|
||||
: base(attribute)
|
||||
public DataTypeAttributeAdapter(DataTypeAttribute attribute, string ruleName, IStringLocalizer stringLocalizer)
|
||||
: base(attribute, stringLocalizer)
|
||||
{
|
||||
if (string.IsNullOrEmpty(ruleName))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
// 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 Microsoft.AspNet.Mvc.DataAnnotations.Internal;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
|
||||
|
||||
namespace Microsoft.Framework.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for configuring MVC data annotations localization.
|
||||
/// </summary>
|
||||
public static class MvcDataAnnotationsMvcBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds MVC data annotations localization to the application.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
|
||||
/// <returns>The <see cref="IMvcBuilder"/>.</returns>
|
||||
public static IMvcBuilder AddDataAnnotationsLocalization(this IMvcBuilder builder)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
return AddDataAnnotationsLocalization(builder, setupAction: null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds MVC data annotations localization to the application.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
|
||||
/// <param name="setupAction">The action to configure <see cref="MvcDataAnnotationsLocalizationOptions"/>.
|
||||
/// </param>
|
||||
/// <returns>The <see cref="IMvcBuilder"/>.</returns>
|
||||
public static IMvcBuilder AddDataAnnotationsLocalization(
|
||||
this IMvcBuilder builder,
|
||||
Action<MvcDataAnnotationsLocalizationOptions> setupAction)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
DataAnnotationsLocalizationServices.AddDataAnnotationsLocalizationServices(
|
||||
builder.Services,
|
||||
setupAction);
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,13 +4,22 @@
|
|||
using System;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Mvc.DataAnnotations.Internal;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
|
||||
using Microsoft.Framework.DependencyInjection.Extensions;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
|
||||
namespace Microsoft.Framework.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions for configuring MVC data annotations using an <see cref="IMvcBuilder"/>.
|
||||
/// </summary>
|
||||
public static class MvcDataAnnotationsMvcCoreBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers MVC data annotations.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
|
||||
/// <returns>The <see cref="IMvcBuilder"/>.</returns>
|
||||
public static IMvcCoreBuilder AddDataAnnotations(this IMvcCoreBuilder builder)
|
||||
{
|
||||
if (builder == null)
|
||||
|
|
@ -22,11 +31,39 @@ namespace Microsoft.Framework.DependencyInjection
|
|||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers an action to configure <see cref="MvcDataAnnotationsLocalizationOptions"/> for MVC data
|
||||
/// annotations localization.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
|
||||
/// <param name="setupAction">An <see cref="Action{MvcDataAnnotationsLocalizationOptions}"/>.</param>
|
||||
/// <returns>The <see cref="IMvcBuilder"/>.</returns>
|
||||
public static IMvcCoreBuilder AddDataAnnotationsLocalization(
|
||||
this IMvcCoreBuilder builder,
|
||||
Action<MvcDataAnnotationsLocalizationOptions> setupAction)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
AddDataAnnotationsLocalizationServices(builder.Services, setupAction);
|
||||
return builder;
|
||||
}
|
||||
|
||||
// Internal for testing.
|
||||
internal static void AddDataAnnotationsServices(IServiceCollection services)
|
||||
{
|
||||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, MvcDataAnnotationsMvcOptionsSetup>());
|
||||
}
|
||||
|
||||
// Internal for testing.
|
||||
internal static void AddDataAnnotationsLocalizationServices(
|
||||
IServiceCollection services,
|
||||
Action<MvcDataAnnotationsLocalizationOptions> setupAction)
|
||||
{
|
||||
DataAnnotationsLocalizationServices.AddDataAnnotationsLocalizationServices(services, setupAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
// 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 Microsoft.AspNet.Mvc.ModelBinding.Validation;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.DependencyInjection.Extensions;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.DataAnnotations.Internal
|
||||
{
|
||||
public static class DataAnnotationsLocalizationServices
|
||||
{
|
||||
public static void AddDataAnnotationsLocalizationServices(
|
||||
IServiceCollection services,
|
||||
Action<MvcDataAnnotationsLocalizationOptions> setupAction)
|
||||
{
|
||||
services.AddLocalization();
|
||||
|
||||
if (setupAction != null)
|
||||
{
|
||||
services.Configure(setupAction);
|
||||
}
|
||||
else
|
||||
{
|
||||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Transient
|
||||
<IConfigureOptions<MvcDataAnnotationsLocalizationOptions>,
|
||||
MvcDataAnnotationsLocalizationOptionsSetup>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
// 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 Microsoft.AspNet.Mvc.ModelBinding.Validation;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.DataAnnotations.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets up default options for <see cref="MvcDataAnnotationsLocalizationOptions"/>.
|
||||
/// </summary>
|
||||
public class MvcDataAnnotationsLocalizationOptionsSetup : ConfigureOptions<MvcDataAnnotationsLocalizationOptions>
|
||||
{
|
||||
public MvcDataAnnotationsLocalizationOptionsSetup()
|
||||
: base(ConfigureMvc)
|
||||
{
|
||||
}
|
||||
|
||||
public static void ConfigureMvc(MvcDataAnnotationsLocalizationOptions options)
|
||||
{
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
options.DataAnnotationLocalizerProvider = (modelType, stringLocalizerFactory) =>
|
||||
stringLocalizerFactory.Create(modelType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,11 @@
|
|||
// 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 Microsoft.AspNet.Mvc.ModelBinding.Metadata;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.Localization;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.DataAnnotations.Internal
|
||||
|
|
@ -12,15 +15,23 @@ namespace Microsoft.AspNet.Mvc.DataAnnotations.Internal
|
|||
/// </summary>
|
||||
public class MvcDataAnnotationsMvcOptionsSetup : ConfigureOptions<MvcOptions>
|
||||
{
|
||||
public MvcDataAnnotationsMvcOptionsSetup()
|
||||
: base(ConfigureMvc)
|
||||
public MvcDataAnnotationsMvcOptionsSetup(IServiceProvider serviceProvider)
|
||||
: base(options => ConfigureMvc(options, serviceProvider))
|
||||
{
|
||||
}
|
||||
|
||||
public static void ConfigureMvc(MvcOptions options)
|
||||
public static void ConfigureMvc(MvcOptions options, IServiceProvider serviceProvider)
|
||||
{
|
||||
var dataAnnotationLocalizationOptions =
|
||||
serviceProvider.GetRequiredService<IOptions<MvcDataAnnotationsLocalizationOptions>>();
|
||||
|
||||
// This service will be registered only if AddDataAnnotationsLocalization() is added to service collection.
|
||||
var stringLocalizerFactory = serviceProvider.GetService<IStringLocalizerFactory>();
|
||||
|
||||
options.ModelMetadataDetailsProviders.Add(new DataAnnotationsMetadataProvider());
|
||||
options.ModelValidatorProviders.Add(new DataAnnotationsModelValidatorProvider());
|
||||
options.ModelValidatorProviders.Add(new DataAnnotationsModelValidatorProvider(
|
||||
dataAnnotationLocalizationOptions,
|
||||
stringLocalizerFactory));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,13 +4,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.Framework.Localization;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||
{
|
||||
public class MaxLengthAttributeAdapter : DataAnnotationsClientModelValidator<MaxLengthAttribute>
|
||||
{
|
||||
public MaxLengthAttributeAdapter(MaxLengthAttribute attribute)
|
||||
: base(attribute)
|
||||
public MaxLengthAttributeAdapter(MaxLengthAttribute attribute, IStringLocalizer stringLocalizer)
|
||||
: base(attribute, stringLocalizer)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,13 +4,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.Framework.Localization;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||
{
|
||||
public class MinLengthAttributeAdapter : DataAnnotationsClientModelValidator<MinLengthAttribute>
|
||||
{
|
||||
public MinLengthAttributeAdapter(MinLengthAttribute attribute)
|
||||
: base(attribute)
|
||||
public MinLengthAttributeAdapter(MinLengthAttribute attribute, IStringLocalizer stringLocalizer)
|
||||
: base(attribute, stringLocalizer)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
// 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 Microsoft.Framework.Localization;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides programmatic configuration for DataAnnotations localization in the MVC framework.
|
||||
/// </summary>
|
||||
public class MvcDataAnnotationsLocalizationOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// The delegate to invoke for creating <see cref="IStringLocalizer"/>.
|
||||
/// </summary>
|
||||
public Func<Type, IStringLocalizerFactory, IStringLocalizer> DataAnnotationLocalizerProvider;
|
||||
}
|
||||
}
|
||||
|
|
@ -4,13 +4,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.Framework.Localization;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||
{
|
||||
public class RangeAttributeAdapter : DataAnnotationsClientModelValidator<RangeAttribute>
|
||||
{
|
||||
public RangeAttributeAdapter(RangeAttribute attribute)
|
||||
: base(attribute)
|
||||
public RangeAttributeAdapter(RangeAttribute attribute, IStringLocalizer stringLocalizer)
|
||||
: base(attribute, stringLocalizer)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,13 +4,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.Framework.Localization;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||
{
|
||||
public class RegularExpressionAttributeAdapter : DataAnnotationsClientModelValidator<RegularExpressionAttribute>
|
||||
{
|
||||
public RegularExpressionAttributeAdapter(RegularExpressionAttribute attribute)
|
||||
: base(attribute)
|
||||
public RegularExpressionAttributeAdapter(RegularExpressionAttribute attribute, IStringLocalizer stringLocalizer)
|
||||
: base(attribute, stringLocalizer)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,13 +4,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.Framework.Localization;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||
{
|
||||
public class RequiredAttributeAdapter : DataAnnotationsClientModelValidator<RequiredAttribute>
|
||||
{
|
||||
public RequiredAttributeAdapter(RequiredAttribute attribute)
|
||||
: base(attribute)
|
||||
public RequiredAttributeAdapter(RequiredAttribute attribute, IStringLocalizer stringLocalizer)
|
||||
: base(attribute, stringLocalizer)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,13 +4,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.Framework.Localization;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||
{
|
||||
public class StringLengthAttributeAdapter : DataAnnotationsClientModelValidator<StringLengthAttribute>
|
||||
{
|
||||
public StringLengthAttributeAdapter(StringLengthAttribute attribute)
|
||||
: base(attribute)
|
||||
public StringLengthAttributeAdapter(StringLengthAttribute attribute, IStringLocalizer stringLocalizer)
|
||||
: base(attribute, stringLocalizer)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@
|
|||
"dependencies": {
|
||||
"Microsoft.AspNet.Mvc.Core": "6.0.0-*",
|
||||
"Microsoft.Framework.ClosedGenericMatcher.Sources": { "version": "1.0.0-*", "type": "build" },
|
||||
"Microsoft.Framework.CopyOnWriteDictionary.Sources": { "version": "1.0.0-*", "type": "build" }
|
||||
"Microsoft.Framework.CopyOnWriteDictionary.Sources": { "version": "1.0.0-*", "type": "build" },
|
||||
"Microsoft.Framework.Localization": "1.0.0-*"
|
||||
},
|
||||
|
||||
"frameworks": {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
// 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 Microsoft.AspNet.Mvc.ModelBinding.Validation;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.Localization;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewFeatures.Internal
|
||||
|
|
@ -14,16 +17,24 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures.Internal
|
|||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="MvcViewOptionsSetup"/>.
|
||||
/// </summary>
|
||||
public MvcViewOptionsSetup()
|
||||
: base(ConfigureMvc)
|
||||
public MvcViewOptionsSetup(IServiceProvider serviceProvider)
|
||||
: base(options => ConfigureMvc(options, serviceProvider))
|
||||
{
|
||||
}
|
||||
|
||||
public static void ConfigureMvc(MvcViewOptions options)
|
||||
public static void ConfigureMvc(
|
||||
MvcViewOptions options,
|
||||
IServiceProvider serviceProvider)
|
||||
{
|
||||
var dataAnnotationsLocalizationOptions =
|
||||
serviceProvider.GetRequiredService<IOptions<MvcDataAnnotationsLocalizationOptions>>();
|
||||
var stringLocalizerFactory = serviceProvider.GetService<IStringLocalizerFactory>();
|
||||
|
||||
// Set up client validators
|
||||
options.ClientModelValidatorProviders.Add(new DefaultClientModelValidatorProvider());
|
||||
options.ClientModelValidatorProviders.Add(new DataAnnotationsClientModelValidatorProvider());
|
||||
options.ClientModelValidatorProviders.Add(new DataAnnotationsClientModelValidatorProvider(
|
||||
dataAnnotationsLocalizationOptions,
|
||||
stringLocalizerFactory));
|
||||
options.ClientModelValidatorProviders.Add(new NumericClientModelValidatorProvider());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -242,7 +242,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
{
|
||||
ModelBinder = innerBinder ?? CreateIntBinder(),
|
||||
MetadataProvider = metataProvider,
|
||||
ValidatorProvider = new DataAnnotationsModelValidatorProvider()
|
||||
ValidatorProvider = new DataAnnotationsModelValidatorProvider(
|
||||
new TestOptionsManager<MvcDataAnnotationsLocalizationOptions>(),
|
||||
stringLocalizerFactory: null)
|
||||
}
|
||||
};
|
||||
return bindingContext;
|
||||
|
|
|
|||
|
|
@ -72,7 +72,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
new MutableObjectModelBinder()
|
||||
};
|
||||
|
||||
var validator = new DataAnnotationsModelValidatorProvider();
|
||||
var validator = new DataAnnotationsModelValidatorProvider(
|
||||
new TestOptionsManager<MvcDataAnnotationsLocalizationOptions>(),
|
||||
stringLocalizerFactory: null);
|
||||
var model = new MyModel();
|
||||
var modelStateDictionary = new ModelStateDictionary();
|
||||
var values = new Dictionary<string, object>
|
||||
|
|
@ -111,7 +113,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
new MutableObjectModelBinder()
|
||||
};
|
||||
|
||||
var validator = new DataAnnotationsModelValidatorProvider();
|
||||
var validator = new DataAnnotationsModelValidatorProvider(
|
||||
new TestOptionsManager<MvcDataAnnotationsLocalizationOptions>(),
|
||||
stringLocalizerFactory: null);
|
||||
var model = new MyModel { MyProperty = "Old-Value" };
|
||||
var modelStateDictionary = new ModelStateDictionary();
|
||||
var values = new Dictionary<string, object>
|
||||
|
|
@ -185,7 +189,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
new MutableObjectModelBinder()
|
||||
};
|
||||
|
||||
var validator = new DataAnnotationsModelValidatorProvider();
|
||||
var validator = new DataAnnotationsModelValidatorProvider(
|
||||
new TestOptionsManager<MvcDataAnnotationsLocalizationOptions>(),
|
||||
stringLocalizerFactory: null);
|
||||
var model = new MyModel {
|
||||
MyProperty = "Old-Value",
|
||||
IncludedProperty = "Old-IncludedPropertyValue",
|
||||
|
|
@ -274,7 +280,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
new MutableObjectModelBinder()
|
||||
};
|
||||
|
||||
var validator = new DataAnnotationsModelValidatorProvider();
|
||||
var validator = new DataAnnotationsModelValidatorProvider(
|
||||
new TestOptionsManager<MvcDataAnnotationsLocalizationOptions>(),
|
||||
stringLocalizerFactory: null);
|
||||
var model = new MyModel
|
||||
{
|
||||
MyProperty = "Old-Value",
|
||||
|
|
@ -326,7 +334,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
new MutableObjectModelBinder()
|
||||
};
|
||||
|
||||
var validator = new DataAnnotationsModelValidatorProvider();
|
||||
var validator = new DataAnnotationsModelValidatorProvider(
|
||||
new TestOptionsManager<MvcDataAnnotationsLocalizationOptions>(),
|
||||
stringLocalizerFactory: null);
|
||||
var model = new MyModel
|
||||
{
|
||||
MyProperty = "Old-Value",
|
||||
|
|
@ -532,7 +542,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
new MutableObjectModelBinder()
|
||||
};
|
||||
|
||||
var validator = new DataAnnotationsModelValidatorProvider();
|
||||
var validator = new DataAnnotationsModelValidatorProvider(
|
||||
new TestOptionsManager<MvcDataAnnotationsLocalizationOptions>(),
|
||||
stringLocalizerFactory: null);
|
||||
var model = new MyModel
|
||||
{
|
||||
MyProperty = "Old-Value",
|
||||
|
|
@ -623,7 +635,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
new MutableObjectModelBinder()
|
||||
};
|
||||
|
||||
var validator = new DataAnnotationsModelValidatorProvider();
|
||||
var validator = new DataAnnotationsModelValidatorProvider(
|
||||
new TestOptionsManager<MvcDataAnnotationsLocalizationOptions>(),
|
||||
stringLocalizerFactory: null);
|
||||
var model = new MyModel { MyProperty = "Old-Value" };
|
||||
var modelStateDictionary = new ModelStateDictionary();
|
||||
var values = new Dictionary<string, object>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
var metadata = metadataProvider.GetMetadataForProperty(typeof(PropertyDisplayNameModel), "MyProperty");
|
||||
|
||||
var attribute = new CompareAttribute("OtherProperty");
|
||||
var adapter = new CompareAttributeAdapter(attribute);
|
||||
var adapter = new CompareAttributeAdapter(attribute, stringLocalizer: null);
|
||||
|
||||
var serviceCollection = new ServiceCollection();
|
||||
var requestServices = serviceCollection.BuildServiceProvider();
|
||||
|
|
@ -50,7 +50,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
var serviceCollection = new ServiceCollection();
|
||||
var requestServices = serviceCollection.BuildServiceProvider();
|
||||
var context = new ClientModelValidationContext(metadata, metadataProvider, requestServices);
|
||||
var adapter = new CompareAttributeAdapter(attribute);
|
||||
var adapter = new CompareAttributeAdapter(attribute, stringLocalizer: null);
|
||||
|
||||
// Act
|
||||
var rules = adapter.GetClientValidationRules(context);
|
||||
|
|
@ -76,7 +76,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
var serviceCollection = new ServiceCollection();
|
||||
var requestServices = serviceCollection.BuildServiceProvider();
|
||||
var context = new ClientModelValidationContext(metadata, metadataProvider, requestServices);
|
||||
var adapter = new CompareAttributeAdapter(attribute);
|
||||
var adapter = new CompareAttributeAdapter(attribute, stringLocalizer: null);
|
||||
|
||||
// Act
|
||||
var rules = adapter.GetClientValidationRules(context);
|
||||
|
|
@ -102,7 +102,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
var serviceCollection = new ServiceCollection();
|
||||
var requestServices = serviceCollection.BuildServiceProvider();
|
||||
var context = new ClientModelValidationContext(metadata, metadataProvider, requestServices);
|
||||
var adapter = new CompareAttributeAdapter(attribute);
|
||||
var adapter = new CompareAttributeAdapter(attribute, stringLocalizer: null);
|
||||
|
||||
// Act
|
||||
var rules = adapter.GetClientValidationRules(context);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
public void GetValidators_AddsRequiredAttribute_ForIsRequiredTrue()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsClientModelValidatorProvider();
|
||||
var provider = new DataAnnotationsClientModelValidatorProvider(
|
||||
new TestOptionsManager<MvcDataAnnotationsLocalizationOptions>(),
|
||||
stringLocalizerFactory: null);
|
||||
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(
|
||||
typeof(DummyRequiredAttributeHelperClass),
|
||||
|
|
@ -37,7 +39,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
public void GetValidators_DoesNotAddRequiredAttribute_ForIsRequiredFalse()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsClientModelValidatorProvider();
|
||||
var provider = new DataAnnotationsClientModelValidatorProvider(
|
||||
new TestOptionsManager<MvcDataAnnotationsLocalizationOptions>(),
|
||||
stringLocalizerFactory: null);
|
||||
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(
|
||||
typeof(DummyRequiredAttributeHelperClass),
|
||||
|
|
@ -56,7 +60,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
public void GetValidators_DoesNotAddExtraRequiredAttribute_IfAttributeIsSpecifiedExplicitly()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsClientModelValidatorProvider();
|
||||
var provider = new DataAnnotationsClientModelValidatorProvider(
|
||||
new TestOptionsManager<MvcDataAnnotationsLocalizationOptions>(),
|
||||
stringLocalizerFactory: null);
|
||||
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(
|
||||
typeof(DummyRequiredAttributeHelperClass),
|
||||
|
|
@ -122,11 +128,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
Type expectedAdapterType)
|
||||
{
|
||||
// Arrange
|
||||
var adapters = new DataAnnotationsClientModelValidatorProvider().AttributeFactories;
|
||||
var adapters = new DataAnnotationsClientModelValidatorProvider(
|
||||
new TestOptionsManager<MvcDataAnnotationsLocalizationOptions>(),
|
||||
stringLocalizerFactory: null)
|
||||
.AttributeFactories;
|
||||
var adapterFactory = adapters.Single(kvp => kvp.Key == attribute.GetType()).Value;
|
||||
|
||||
// Act
|
||||
var adapter = adapterFactory(attribute);
|
||||
var adapter = adapterFactory(attribute, stringLocalizer: null);
|
||||
|
||||
// Assert
|
||||
Assert.IsType(expectedAdapterType, adapter);
|
||||
|
|
@ -150,11 +159,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
string expectedRuleName)
|
||||
{
|
||||
// Arrange
|
||||
var adapters = new DataAnnotationsClientModelValidatorProvider().AttributeFactories;
|
||||
var adapters = new DataAnnotationsClientModelValidatorProvider(
|
||||
new TestOptionsManager<MvcDataAnnotationsLocalizationOptions>(),
|
||||
stringLocalizerFactory: null)
|
||||
.AttributeFactories;
|
||||
var adapterFactory = adapters.Single(kvp => kvp.Key == attribute.GetType()).Value;
|
||||
|
||||
// Act
|
||||
var adapter = adapterFactory(attribute);
|
||||
var adapter = adapterFactory(attribute, stringLocalizer: null);
|
||||
|
||||
// Assert
|
||||
var dataTypeAdapter = Assert.IsType<DataTypeAttributeAdapter>(adapter);
|
||||
|
|
@ -165,7 +177,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
public void UnknownValidationAttribute_IsNotAddedAsValidator()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsClientModelValidatorProvider();
|
||||
var provider = new DataAnnotationsClientModelValidatorProvider(
|
||||
new TestOptionsManager<MvcDataAnnotationsLocalizationOptions>(),
|
||||
stringLocalizerFactory: null);
|
||||
var metadata = _metadataProvider.GetMetadataForType(typeof(DummyClassWithDummyValidationAttribute));
|
||||
|
||||
var providerContext = new ClientValidatorProviderContext(metadata);
|
||||
|
|
|
|||
|
|
@ -21,7 +21,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
public void GetValidators_ReturnsValidatorForIValidatableObject()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsModelValidatorProvider();
|
||||
var provider = new DataAnnotationsModelValidatorProvider(
|
||||
new TestOptionsManager<MvcDataAnnotationsLocalizationOptions>(),
|
||||
stringLocalizerFactory: null);
|
||||
var mockValidatable = Mock.Of<IValidatableObject>();
|
||||
var metadata = _metadataProvider.GetMetadataForType(mockValidatable.GetType());
|
||||
|
||||
|
|
@ -40,7 +42,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
public void UnknownValidationAttributeGetsDefaultAdapter()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsModelValidatorProvider();
|
||||
var provider = new DataAnnotationsModelValidatorProvider(
|
||||
new TestOptionsManager<MvcDataAnnotationsLocalizationOptions>(),
|
||||
stringLocalizerFactory: null);
|
||||
var metadata = _metadataProvider.GetMetadataForType(typeof(DummyClassWithDummyValidationAttribute));
|
||||
|
||||
var providerContext = new ModelValidatorProviderContext(metadata);
|
||||
|
|
@ -69,7 +73,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
public void IValidatableObjectGetsAValidator()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsModelValidatorProvider();
|
||||
var provider = new DataAnnotationsModelValidatorProvider(
|
||||
new TestOptionsManager<MvcDataAnnotationsLocalizationOptions>(),
|
||||
stringLocalizerFactory: null);
|
||||
var mockValidatable = new Mock<IValidatableObject>();
|
||||
var metadata = _metadataProvider.GetMetadataForType(mockValidatable.Object.GetType());
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using System.ComponentModel.DataAnnotations;
|
|||
using System.Linq;
|
||||
#endif
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.Localization;
|
||||
#if DNX451
|
||||
using Moq;
|
||||
using Moq.Protected;
|
||||
|
|
@ -26,7 +27,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
var attribute = new RequiredAttribute();
|
||||
|
||||
// Act
|
||||
var validator = new DataAnnotationsModelValidator(attribute);
|
||||
var validator = new DataAnnotationsModelValidator(attribute, stringLocalizer : null);
|
||||
|
||||
// Assert
|
||||
Assert.Same(attribute, validator.Attribute);
|
||||
|
|
@ -67,7 +68,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
})
|
||||
.Returns(ValidationResult.Success)
|
||||
.Verifiable();
|
||||
var validator = new DataAnnotationsModelValidator(attribute.Object);
|
||||
var validator = new DataAnnotationsModelValidator(attribute.Object, stringLocalizer: null);
|
||||
var validationContext = CreateValidationContext(modelExplorer);
|
||||
|
||||
// Act
|
||||
|
|
@ -89,7 +90,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
var attribute = new Mock<ValidationAttribute> { CallBase = true };
|
||||
attribute.Setup(a => a.IsValid(modelExplorer.Model)).Returns(true);
|
||||
|
||||
var validator = new DataAnnotationsModelValidator(attribute.Object);
|
||||
var validator = new DataAnnotationsModelValidator(attribute.Object, stringLocalizer: null);
|
||||
var validationContext = CreateValidationContext(modelExplorer);
|
||||
|
||||
// Act
|
||||
|
|
@ -110,7 +111,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
var attribute = new Mock<ValidationAttribute> { CallBase = true };
|
||||
attribute.Setup(a => a.IsValid(modelExplorer.Model)).Returns(false);
|
||||
|
||||
var validator = new DataAnnotationsModelValidator(attribute.Object);
|
||||
var validator = new DataAnnotationsModelValidator(attribute.Object, stringLocalizer: null);
|
||||
var validationContext = CreateValidationContext(modelExplorer);
|
||||
|
||||
// Act
|
||||
|
|
@ -134,7 +135,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
attribute.Protected()
|
||||
.Setup<ValidationResult>("IsValid", ItExpr.IsAny<object>(), ItExpr.IsAny<ValidationContext>())
|
||||
.Returns(ValidationResult.Success);
|
||||
var validator = new DataAnnotationsModelValidator(attribute.Object);
|
||||
var validator = new DataAnnotationsModelValidator(attribute.Object, stringLocalizer: null);
|
||||
var validationContext = CreateValidationContext(modelExplorer);
|
||||
|
||||
// Act
|
||||
|
|
@ -158,7 +159,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
attribute.Protected()
|
||||
.Setup<ValidationResult>("IsValid", ItExpr.IsAny<object>(), ItExpr.IsAny<ValidationContext>())
|
||||
.Returns(new ValidationResult(errorMessage, memberNames: null));
|
||||
var validator = new DataAnnotationsModelValidator(attribute.Object);
|
||||
var validator = new DataAnnotationsModelValidator(attribute.Object, stringLocalizer: null);
|
||||
|
||||
var validationContext = CreateValidationContext(modelExplorer);
|
||||
|
||||
|
|
@ -184,7 +185,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
.Setup<ValidationResult>("IsValid", ItExpr.IsAny<object>(), ItExpr.IsAny<ValidationContext>())
|
||||
.Returns(new ValidationResult(errorMessage, new[] { "FirstName" }));
|
||||
|
||||
var validator = new DataAnnotationsModelValidator(attribute.Object);
|
||||
var validator = new DataAnnotationsModelValidator(attribute.Object, stringLocalizer: null);
|
||||
var validationContext = CreateValidationContext(modelExplorer);
|
||||
|
||||
// Act
|
||||
|
|
@ -207,7 +208,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
.Setup<ValidationResult>("IsValid", ItExpr.IsAny<object>(), ItExpr.IsAny<ValidationContext>())
|
||||
.Returns(new ValidationResult("Name error", new[] { "Name" }));
|
||||
|
||||
var validator = new DataAnnotationsModelValidator(attribute.Object);
|
||||
var validator = new DataAnnotationsModelValidator(attribute.Object, stringLocalizer: null);
|
||||
var validationContext = CreateValidationContext(modelExplorer);
|
||||
|
||||
// Act
|
||||
|
|
@ -217,15 +218,46 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
ModelValidationResult validationResult = Assert.Single(results);
|
||||
Assert.Equal("Name", validationResult.MemberName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidateWithIsValidFalse_StringLocalizerReturnsLocalizerErrorMessage()
|
||||
{
|
||||
// Arrange
|
||||
var modelExplorer = _metadataProvider
|
||||
.GetModelExplorerForType(typeof(string), "Hello")
|
||||
.GetExplorerForProperty("Length");
|
||||
|
||||
var attribute = new Mock<ValidationAttribute> { CallBase = true };
|
||||
attribute.Setup(a => a.IsValid(modelExplorer.Model)).Returns(false);
|
||||
|
||||
attribute.Object.ErrorMessage = "Length";
|
||||
|
||||
var localizedString = new LocalizedString("Length", "Longueur est invalide");
|
||||
var stringLocalizer = new Mock<IStringLocalizer>();
|
||||
stringLocalizer.Setup(s => s["Length"]).Returns(localizedString);
|
||||
|
||||
var validator = new DataAnnotationsModelValidator(attribute.Object, stringLocalizer.Object);
|
||||
var validationContext = CreateValidationContext(modelExplorer);
|
||||
|
||||
// Act
|
||||
var result = validator.Validate(validationContext);
|
||||
|
||||
// Assert
|
||||
var validationResult = result.Single();
|
||||
Assert.Equal("", validationResult.MemberName);
|
||||
Assert.Equal("Longueur est invalide", validationResult.Message);
|
||||
}
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void IsRequiredTests()
|
||||
{
|
||||
// Arrange & Act & Assert
|
||||
Assert.False(new DataAnnotationsModelValidator(new RangeAttribute(10, 20)).IsRequired);
|
||||
Assert.True(new DataAnnotationsModelValidator(new RequiredAttribute()).IsRequired);
|
||||
Assert.True(new DataAnnotationsModelValidator(new DerivedRequiredAttribute()).IsRequired);
|
||||
Assert.False(new DataAnnotationsModelValidator(new RangeAttribute(10, 20), stringLocalizer: null)
|
||||
.IsRequired);
|
||||
Assert.True(new DataAnnotationsModelValidator(new RequiredAttribute(), stringLocalizer: null).IsRequired);
|
||||
Assert.True(new DataAnnotationsModelValidator(new DerivedRequiredAttribute(), stringLocalizer: null)
|
||||
.IsRequired);
|
||||
}
|
||||
|
||||
private static ModelValidationContext CreateValidationContext(ModelExplorer modelExplorer)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.AspNet.Testing;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.Localization;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||
|
|
@ -18,7 +20,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
var provider = TestModelMetadataProvider.CreateDefaultProvider();
|
||||
var metadata = provider.GetMetadataForProperty(typeof(string), "Length");
|
||||
var attribute = new MaxLengthAttribute(10);
|
||||
var adapter = new MaxLengthAttributeAdapter(attribute);
|
||||
var adapter = new MaxLengthAttributeAdapter(attribute, stringLocalizer: null);
|
||||
var serviceCollection = new ServiceCollection();
|
||||
var requestServices = serviceCollection.BuildServiceProvider();
|
||||
var context = new ClientModelValidationContext(metadata, provider, requestServices);
|
||||
|
|
@ -44,7 +46,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
var provider = TestModelMetadataProvider.CreateDefaultProvider();
|
||||
var metadata = provider.GetMetadataForProperty(typeof(string), propertyName);
|
||||
var attribute = new MaxLengthAttribute(5) { ErrorMessage = message };
|
||||
var adapter = new MaxLengthAttributeAdapter(attribute);
|
||||
var adapter = new MaxLengthAttributeAdapter(attribute, stringLocalizer: null);
|
||||
var serviceCollection = new ServiceCollection();
|
||||
var requestServices = serviceCollection.BuildServiceProvider();
|
||||
var context = new ClientModelValidationContext(metadata, provider, requestServices);
|
||||
|
|
@ -59,5 +61,38 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
Assert.Equal(5, rule.ValidationParameters["max"]);
|
||||
Assert.Equal("Length must be at most 5", rule.ErrorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
#if DNX451
|
||||
[Fact]
|
||||
[ReplaceCulture]
|
||||
public void ClientRulesWithMaxLengthAttribute_StringLocalizer_ReturnsLocalizedErrorString()
|
||||
{
|
||||
// Arrange
|
||||
var provider = TestModelMetadataProvider.CreateDefaultProvider();
|
||||
var metadata = provider.GetMetadataForProperty(typeof(string), "Length");
|
||||
var errorKey = metadata.GetDisplayName();
|
||||
var attribute = new MaxLengthAttribute(10);
|
||||
attribute.ErrorMessage = errorKey;
|
||||
|
||||
var localizedString = new LocalizedString(errorKey, "Longueur est invalide");
|
||||
var stringLocalizer = new Mock<IStringLocalizer>();
|
||||
stringLocalizer.Setup(s => s[errorKey]).Returns(localizedString);
|
||||
|
||||
var adapter = new MaxLengthAttributeAdapter(attribute, stringLocalizer.Object);
|
||||
var serviceCollection = new ServiceCollection();
|
||||
var requestServices = serviceCollection.BuildServiceProvider();
|
||||
var context = new ClientModelValidationContext(metadata, provider, requestServices);
|
||||
|
||||
// Act
|
||||
var rules = adapter.GetClientValidationRules(context);
|
||||
|
||||
// Assert
|
||||
var rule = Assert.Single(rules);
|
||||
Assert.Equal("maxlength", rule.ValidationType);
|
||||
Assert.Equal(1, rule.ValidationParameters.Count);
|
||||
Assert.Equal(10, rule.ValidationParameters["max"]);
|
||||
Assert.Equal("Longueur est invalide", rule.ErrorMessage);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
var provider = TestModelMetadataProvider.CreateDefaultProvider();
|
||||
var metadata = provider.GetMetadataForProperty(typeof(string), "Length");
|
||||
var attribute = new MinLengthAttribute(6);
|
||||
var adapter = new MinLengthAttributeAdapter(attribute);
|
||||
var adapter = new MinLengthAttributeAdapter(attribute, stringLocalizer: null);
|
||||
var serviceCollection = new ServiceCollection();
|
||||
var requestServices = serviceCollection.BuildServiceProvider();
|
||||
var context = new ClientModelValidationContext(metadata, provider, requestServices);
|
||||
|
|
@ -44,7 +44,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
var provider = TestModelMetadataProvider.CreateDefaultProvider();
|
||||
var metadata = provider.GetMetadataForProperty(typeof(string), propertyName);
|
||||
var attribute = new MinLengthAttribute(2) { ErrorMessage = message };
|
||||
var adapter = new MinLengthAttributeAdapter(attribute);
|
||||
var adapter = new MinLengthAttributeAdapter(attribute, stringLocalizer: null);
|
||||
var serviceCollection = new ServiceCollection();
|
||||
var requestServices = serviceCollection.BuildServiceProvider();
|
||||
var context = new ClientModelValidationContext(metadata, provider, requestServices);
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
var provider = TestModelMetadataProvider.CreateDefaultProvider();
|
||||
var metadata = provider.GetMetadataForProperty(typeof(string), "Length");
|
||||
var attribute = new RangeAttribute(typeof(decimal), "0", "100");
|
||||
var adapter = new RangeAttributeAdapter(attribute);
|
||||
var adapter = new RangeAttributeAdapter(attribute, stringLocalizer: null);
|
||||
var serviceCollection = new ServiceCollection();
|
||||
var requestServices = serviceCollection.BuildServiceProvider();
|
||||
var context = new ClientModelValidationContext(metadata, provider, requestServices);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
var provider = TestModelMetadataProvider.CreateDefaultProvider();
|
||||
var metadata = provider.GetMetadataForProperty(typeof(string), "Length");
|
||||
var attribute = new RequiredAttribute();
|
||||
var adapter = new RequiredAttributeAdapter(attribute);
|
||||
var adapter = new RequiredAttributeAdapter(attribute, stringLocalizer: null);
|
||||
var serviceCollection = new ServiceCollection();
|
||||
var requestServices = serviceCollection.BuildServiceProvider();
|
||||
var context = new ClientModelValidationContext(metadata, provider, requestServices);
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
var provider = TestModelMetadataProvider.CreateDefaultProvider();
|
||||
var metadata = provider.GetMetadataForProperty(typeof(string), "Length");
|
||||
var attribute = new StringLengthAttribute(8);
|
||||
var adapter = new StringLengthAttributeAdapter(attribute);
|
||||
var adapter = new StringLengthAttributeAdapter(attribute, stringLocalizer: null);
|
||||
var serviceCollection = new ServiceCollection();
|
||||
var requestServices = serviceCollection.BuildServiceProvider();
|
||||
var context = new ClientModelValidationContext(metadata, provider, requestServices);
|
||||
|
|
@ -42,7 +42,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
var provider = TestModelMetadataProvider.CreateDefaultProvider();
|
||||
var metadata = provider.GetMetadataForProperty(typeof(string), "Length");
|
||||
var attribute = new StringLengthAttribute(10) { MinimumLength = 3 };
|
||||
var adapter = new StringLengthAttributeAdapter(attribute);
|
||||
var adapter = new StringLengthAttributeAdapter(attribute, stringLocalizer: null);
|
||||
var serviceCollection = new ServiceCollection();
|
||||
var requestServices = serviceCollection.BuildServiceProvider();
|
||||
var context = new ClientModelValidationContext(metadata, provider, requestServices);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using System.Reflection;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Testing;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||
|
|
@ -121,5 +122,32 @@ Salut John ! Vous êtes en 2015 an aujourd'hui est Thursday";
|
|||
// Assert
|
||||
Assert.Equal(expected, body.Trim());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Localization_InvalidModel_ValidationAttributes_ReturnsLocalizedErrorMessage()
|
||||
{
|
||||
// Arrange
|
||||
var expected =
|
||||
@"<span class=""field-validation-error"" data-valmsg-for=""Name"" data-valmsg-replace=""true"">Nom non valide. Longueur minimale de nom est 4</span>
|
||||
<span class=""field-validation-error"" data-valmsg-for=""Product.ProductName"" data-valmsg-replace=""true"">Nom du produit est invalide</span>
|
||||
<div class=""editor-label""><label for=""Name"">Name</label></div>
|
||||
<div class=""editor-field""><input class=""input-validation-error text-box single-line"" data-val=""true"" data-val-minlength=""Nom non valide. Longueur minimale de nom est 4"" data-val-minlength-min=""4"" id=""Name"" name=""Name"" type=""text"" value=""A"" /> <span class=""field-validation-error"" data-valmsg-for=""Name"" data-valmsg-replace=""true"">Nom non valide. Longueur minimale de nom est 4</span></div>
|
||||
|
||||
<div class=""editor-label""><label for=""Product_ProductName"">ProductName</label></div>
|
||||
<div class=""editor-field""><input class=""input-validation-error text-box single-line"" data-val=""true"" data-val-required=""Nom du produit est invalide"" id=""Product_ProductName"" name=""Product.ProductName"" type=""text"" value="""" /> <span class=""field-validation-error"" data-valmsg-for=""Product.ProductName"" data-valmsg-replace=""true"">Nom du produit est invalide</span></div>";
|
||||
|
||||
var cultureCookie = "c=fr|uic=fr";
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/Home/GetInvalidUser");
|
||||
request.Headers.Add(
|
||||
"Cookie",
|
||||
new CookieHeaderValue("ASPNET_CULTURE", cultureCookie).ToString());
|
||||
|
||||
// Act
|
||||
var response = await Client.SendAsync(request);
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, body.Trim(), ignoreLineEndingDifferences: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
// 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 Microsoft.AspNet.Mvc.DataAnnotations.Internal;
|
||||
using Microsoft.AspNet.Mvc.Formatters.Json.Internal;
|
||||
using Microsoft.AspNet.Mvc.Internal;
|
||||
using Microsoft.AspNet.Mvc.TestCommon;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||
|
|
@ -15,7 +16,10 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
|||
{
|
||||
Value = new MvcOptions();
|
||||
MvcCoreMvcOptionsSetup.ConfigureMvc(Value);
|
||||
MvcDataAnnotationsMvcOptionsSetup.ConfigureMvc(Value);
|
||||
var collection = new ServiceCollection().AddOptions();
|
||||
MvcDataAnnotationsMvcOptionsSetup.ConfigureMvc(
|
||||
Value,
|
||||
collection.BuildServiceProvider());
|
||||
MvcJsonMvcOptionsSetup.ConfigureMvc(Value, SerializerSettingsProvider.CreateSerializerSettings());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
var providers = new IClientModelValidatorProvider[]
|
||||
{
|
||||
new DefaultClientModelValidatorProvider(),
|
||||
new DataAnnotationsClientModelValidatorProvider(),
|
||||
new DataAnnotationsClientModelValidatorProvider(
|
||||
new TestOptionsManager<MvcDataAnnotationsLocalizationOptions>(),
|
||||
stringLocalizerFactory: null),
|
||||
};
|
||||
|
||||
return new TestClientModelValidatorProvider(providers);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
|||
var providers = new IModelValidatorProvider[]
|
||||
{
|
||||
new DefaultModelValidatorProvider(),
|
||||
new DataAnnotationsModelValidatorProvider(),
|
||||
new DataAnnotationsModelValidatorProvider(
|
||||
new TestOptionsManager<MvcDataAnnotationsLocalizationOptions>(),
|
||||
stringLocalizerFactory: null),
|
||||
};
|
||||
|
||||
return new TestModelValidatorProvider(providers);
|
||||
|
|
|
|||
|
|
@ -1753,7 +1753,9 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
{
|
||||
ModelBinder = binder,
|
||||
ValueProvider = provider,
|
||||
ValidatorProvider = new DataAnnotationsModelValidatorProvider()
|
||||
ValidatorProvider = new DataAnnotationsModelValidatorProvider(
|
||||
options: null,
|
||||
stringLocalizerFactory: null)
|
||||
};
|
||||
|
||||
return new TestableController()
|
||||
|
|
|
|||
|
|
@ -219,7 +219,13 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
{
|
||||
options.HtmlHelperOptions.IdAttributeDotReplacement = idAttributeDotReplacement;
|
||||
}
|
||||
options.ClientModelValidatorProviders.Add(new DataAnnotationsClientModelValidatorProvider());
|
||||
var localizationOptionsAccesor = new Mock<IOptions<MvcDataAnnotationsLocalizationOptions>>();
|
||||
|
||||
localizationOptionsAccesor.SetupGet(o => o.Value).Returns(new MvcDataAnnotationsLocalizationOptions());
|
||||
|
||||
options.ClientModelValidatorProviders.Add(new DataAnnotationsClientModelValidatorProvider(
|
||||
localizationOptionsAccesor.Object,
|
||||
stringLocalizerFactory: null));
|
||||
var optionsAccessor = new Mock<IOptions<MvcViewOptions>>();
|
||||
optionsAccessor
|
||||
.SetupGet(o => o.Value)
|
||||
|
|
@ -235,6 +241,9 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
serviceProvider
|
||||
.Setup(s => s.GetService(typeof(IViewComponentHelper)))
|
||||
.Returns(new Mock<IViewComponentHelper>().Object);
|
||||
serviceProvider
|
||||
.Setup(s => s.GetService(typeof(IViewComponentHelper)))
|
||||
.Returns(new Mock<IViewComponentHelper>().Object);
|
||||
|
||||
httpContext.RequestServices = serviceProvider.Object;
|
||||
if (htmlGenerator == null)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// 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 LocalizationWebSite.Models;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Mvc.Localization;
|
||||
|
||||
|
|
@ -25,5 +26,17 @@ namespace LocalizationWebSite.Controllers
|
|||
ViewData["Message"] = _localizer["Learn More"];
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult GetInvalidUser()
|
||||
{
|
||||
var user = new User
|
||||
{
|
||||
Name = "A",
|
||||
Product = new Product()
|
||||
};
|
||||
|
||||
TryValidateModel(user);
|
||||
return View(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
// 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;
|
||||
|
||||
namespace LocalizationWebSite.Models
|
||||
{
|
||||
public class User
|
||||
{
|
||||
[MinLength(4, ErrorMessage = "Name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
public Product Product { get; set; }
|
||||
}
|
||||
|
||||
public class Product
|
||||
{
|
||||
[Required(ErrorMessage = "ProductName")]
|
||||
public string ProductName { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="ProductName" xml:space="preserve">
|
||||
<value>Nom du produit est invalide</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Name" xml:space="preserve">
|
||||
<value>Nom non valide. Longueur minimale de nom est 4</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -10,7 +10,10 @@ namespace LocalizationWebSite
|
|||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddMvc().AddViewLocalization(options => options.ResourcesPath = "Resources");
|
||||
services
|
||||
.AddMvc()
|
||||
.AddViewLocalization(options => options.ResourcesPath = "Resources")
|
||||
.AddDataAnnotationsLocalization();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
|
|
@ -18,7 +21,7 @@ namespace LocalizationWebSite
|
|||
app.UseCultureReplacer();
|
||||
|
||||
app.UseRequestLocalization();
|
||||
|
||||
|
||||
app.UseMvcWithDefaultRoute();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
@model LocalizationWebSite.Models.User
|
||||
|
||||
@Html.ValidationMessage("Name")
|
||||
@Html.ValidationMessage("Product.ProductName")
|
||||
@Html.EditorForModel()
|
||||
@Html.EditorFor(model => model.Product)
|
||||
|
||||
|
||||
Loading…
Reference in New Issue