Localize DataAnnotations (#5129)
This commit is contained in:
parent
8de4ddc010
commit
889af50318
2
Mvc.sln
2
Mvc.sln
|
|
@ -1,6 +1,6 @@
|
|||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25123.0
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}"
|
||||
EndProject
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using System.Linq;
|
|||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
|
||||
using Microsoft.Extensions.Localization;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
||||
{
|
||||
|
|
@ -20,6 +21,13 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
|||
IDisplayMetadataProvider,
|
||||
IValidationMetadataProvider
|
||||
{
|
||||
private readonly IStringLocalizerFactory _stringLocalizerFactory;
|
||||
|
||||
public DataAnnotationsMetadataProvider(IStringLocalizerFactory stringLocalizerFactory)
|
||||
{
|
||||
_stringLocalizerFactory = stringLocalizerFactory;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void CreateBindingMetadata(BindingMetadataProviderContext context)
|
||||
{
|
||||
|
|
@ -80,11 +88,23 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
|||
displayMetadata.DataTypeName = DataType.Html.ToString();
|
||||
}
|
||||
|
||||
|
||||
var containerType = context.Key.ContainerType ?? context.Key.ModelType;
|
||||
var localizer = _stringLocalizerFactory?.Create(containerType);
|
||||
|
||||
// Description
|
||||
if (displayAttribute != null)
|
||||
{
|
||||
displayMetadata.Description = () => displayAttribute.GetDescription();
|
||||
displayMetadata.Placeholder = () => displayAttribute.GetPrompt();
|
||||
if (localizer != null &&
|
||||
!string.IsNullOrEmpty(displayAttribute.Description) &&
|
||||
displayAttribute.ResourceType == null)
|
||||
{
|
||||
displayMetadata.Description = () => localizer[displayAttribute.Description];
|
||||
}
|
||||
else
|
||||
{
|
||||
displayMetadata.Description = () => displayAttribute.GetDescription();
|
||||
}
|
||||
}
|
||||
|
||||
// DisplayFormatString
|
||||
|
|
@ -96,7 +116,16 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
|||
// DisplayName
|
||||
if (displayAttribute != null)
|
||||
{
|
||||
displayMetadata.DisplayName = () => displayAttribute.GetName();
|
||||
if (localizer != null &&
|
||||
!string.IsNullOrEmpty(displayAttribute.Name) &&
|
||||
displayAttribute.ResourceType == null)
|
||||
{
|
||||
displayMetadata.DisplayName = () => localizer[displayAttribute.Name];
|
||||
}
|
||||
else
|
||||
{
|
||||
displayMetadata.DisplayName = () => displayAttribute.GetName();
|
||||
}
|
||||
}
|
||||
|
||||
// EditFormatString
|
||||
|
|
@ -189,6 +218,21 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
|||
displayMetadata.Order = displayAttribute.GetOrder().Value;
|
||||
}
|
||||
|
||||
// Placeholder
|
||||
if (displayAttribute != null)
|
||||
{
|
||||
if (localizer != null &&
|
||||
!string.IsNullOrEmpty(displayAttribute.Prompt) &&
|
||||
displayAttribute.ResourceType == null)
|
||||
{
|
||||
displayMetadata.Placeholder = () => localizer[displayAttribute.Prompt];
|
||||
}
|
||||
else
|
||||
{
|
||||
displayMetadata.Placeholder = () => displayAttribute.GetPrompt();
|
||||
}
|
||||
}
|
||||
|
||||
// ShowForDisplay
|
||||
if (scaffoldColumnAttribute != null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
|||
var stringLocalizerFactory = serviceProvider.GetService<IStringLocalizerFactory>();
|
||||
var validationAttributeAdapterProvider = serviceProvider.GetRequiredService<IValidationAttributeAdapterProvider>();
|
||||
|
||||
options.ModelMetadataDetailsProviders.Add(new DataAnnotationsMetadataProvider());
|
||||
options.ModelMetadataDetailsProviders.Add(new DataAnnotationsMetadataProvider(stringLocalizerFactory));
|
||||
|
||||
options.ModelValidatorProviders.Add(new DataAnnotationsModelValidatorProvider(
|
||||
validationAttributeAdapterProvider,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ using System.Linq;
|
|||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
||||
|
|
@ -58,7 +60,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
|||
object expected)
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsMetadataProvider();
|
||||
var provider = new DataAnnotationsMetadataProvider(stringLocalizerFactory: null);
|
||||
|
||||
var key = ModelMetadataIdentity.ForType(typeof(string));
|
||||
var context = new DisplayMetadataProviderContext(key, new ModelAttributes(new object[] { attribute }));
|
||||
|
|
@ -75,7 +77,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
|||
public void CreateDisplayMetadata_FindsDisplayFormat_FromDataType()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsMetadataProvider();
|
||||
var provider = new DataAnnotationsMetadataProvider(stringLocalizerFactory: null);
|
||||
|
||||
var dataType = new DataTypeAttribute(DataType.Currency);
|
||||
var displayFormat = dataType.DisplayFormat; // Non-null for DataType.Currency.
|
||||
|
|
@ -95,7 +97,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
|||
public void CreateDisplayMetadata_FindsDisplayFormat_OverridingDataType()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsMetadataProvider();
|
||||
var provider = new DataAnnotationsMetadataProvider(stringLocalizerFactory: null);
|
||||
|
||||
var dataType = new DataTypeAttribute(DataType.Time); // Has a non-null DisplayFormat.
|
||||
var displayFormat = new DisplayFormatAttribute() // But these values override the values from DataType
|
||||
|
|
@ -118,7 +120,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
|||
public void CreateBindingMetadata_EditableAttributeFalse_SetsReadOnlyTrue()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsMetadataProvider();
|
||||
var provider = new DataAnnotationsMetadataProvider(stringLocalizerFactory: null);
|
||||
|
||||
var editable = new EditableAttribute(allowEdit: false);
|
||||
|
||||
|
|
@ -137,7 +139,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
|||
public void CreateBindingMetadata_EditableAttributeTrue_SetsReadOnlyFalse()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsMetadataProvider();
|
||||
var provider = new DataAnnotationsMetadataProvider(stringLocalizerFactory: null);
|
||||
|
||||
var editable = new EditableAttribute(allowEdit: true);
|
||||
|
||||
|
|
@ -152,13 +154,47 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
|||
Assert.False(context.BindingMetadata.IsReadOnly);
|
||||
}
|
||||
|
||||
// This is IMPORTANT. Product code needs to use GetName() instead of .Name. It's easy to regress.
|
||||
[Fact]
|
||||
public void CreateDisplayMetadata_DisplayAttribute_NameFromResources_NullLocalizer()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsMetadataProvider(stringLocalizerFactory: null);
|
||||
|
||||
var display = new DisplayAttribute()
|
||||
{
|
||||
#if USE_REAL_RESOURCES
|
||||
Name = nameof(Test.Resources.DisplayAttribute_Name),
|
||||
ResourceType = typeof(Test.Resources),
|
||||
#else
|
||||
Name = nameof(DataAnnotations.Test.Resources.DisplayAttribute_Name),
|
||||
ResourceType = typeof(TestResources),
|
||||
#endif
|
||||
};
|
||||
|
||||
var attributes = new Attribute[] { display };
|
||||
var key = ModelMetadataIdentity.ForType(typeof(string));
|
||||
var context = new DisplayMetadataProviderContext(key, new ModelAttributes(attributes));
|
||||
|
||||
// Act
|
||||
provider.CreateDisplayMetadata(context);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("name from resources", context.DisplayMetadata.DisplayName());
|
||||
}
|
||||
|
||||
// This is IMPORTANT. Product code needs to use GetName() instead of .Name. It's easy to regress.
|
||||
[Fact]
|
||||
public void CreateDisplayMetadata_DisplayAttribute_NameFromResources()
|
||||
public void CreateDisplayMetadata_DisplayAttribute_NameFromResources_WithLocalizer()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsMetadataProvider();
|
||||
// Nothing on stringLocalizer should be called
|
||||
var stringLocalizer = new Mock<IStringLocalizer>(MockBehavior.Strict);
|
||||
var stringLocalizerFactory = new Mock<IStringLocalizerFactory>();
|
||||
stringLocalizerFactory
|
||||
.Setup(s => s.Create(It.IsAny<Type>()))
|
||||
.Returns(() => stringLocalizer.Object);
|
||||
var provider = new DataAnnotationsMetadataProvider(stringLocalizerFactory.Object);
|
||||
|
||||
var display = new DisplayAttribute()
|
||||
{
|
||||
|
|
@ -184,10 +220,16 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
|||
|
||||
// This is IMPORTANT. Product code needs to use GetDescription() instead of .Description. It's easy to regress.
|
||||
[Fact]
|
||||
public void CreateDisplayMetadata_DisplayAttribute_DescriptionFromResources()
|
||||
public void CreateDisplayMetadata_DisplayAttribute_DescriptionFromResources_WithLocalizer()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsMetadataProvider();
|
||||
// Nothing on stringLocalizer should be called
|
||||
var stringLocalizer = new Mock<IStringLocalizer>(MockBehavior.Strict);
|
||||
var stringLocalizerFactory = new Mock<IStringLocalizerFactory>();
|
||||
stringLocalizerFactory
|
||||
.Setup(s => s.Create(It.IsAny<Type>()))
|
||||
.Returns(() => stringLocalizer.Object);
|
||||
var provider = new DataAnnotationsMetadataProvider(stringLocalizerFactory.Object);
|
||||
|
||||
var display = new DisplayAttribute()
|
||||
{
|
||||
|
|
@ -211,6 +253,141 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
|||
Assert.Equal("description from resources", context.DisplayMetadata.Description());
|
||||
}
|
||||
|
||||
// This is IMPORTANT. Product code needs to use GetDescription() instead of .Description. It's easy to regress.
|
||||
[Fact]
|
||||
public void CreateDisplayMetadata_DisplayAttribute_DescriptionFromResources_NullLocalizer()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsMetadataProvider(stringLocalizerFactory: null);
|
||||
|
||||
var display = new DisplayAttribute()
|
||||
{
|
||||
#if USE_REAL_RESOURCES
|
||||
Description = nameof(Test.Resources.DisplayAttribute_Description),
|
||||
ResourceType = typeof(Test.Resources),
|
||||
#else
|
||||
Description = nameof(DataAnnotations.Test.Resources.DisplayAttribute_Description),
|
||||
ResourceType = typeof(TestResources),
|
||||
#endif
|
||||
};
|
||||
|
||||
var attributes = new Attribute[] { display };
|
||||
var key = ModelMetadataIdentity.ForType(typeof(string));
|
||||
var context = new DisplayMetadataProviderContext(key, new ModelAttributes(attributes));
|
||||
|
||||
// Act
|
||||
provider.CreateDisplayMetadata(context);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("description from resources", context.DisplayMetadata.Description());
|
||||
}
|
||||
|
||||
// This is IMPORTANT. Product code needs to use GetPrompt() instead of .Prompt. It's easy to regress.
|
||||
[Fact]
|
||||
public void CreateDisplayMetadata_DisplayAttribute_PromptFromResources_WithLocalizer()
|
||||
{
|
||||
// Arrange
|
||||
// Nothing on stringLocalizer should be called
|
||||
var stringLocalizer = new Mock<IStringLocalizer>(MockBehavior.Strict);
|
||||
var stringLocalizerFactory = new Mock<IStringLocalizerFactory>();
|
||||
stringLocalizerFactory
|
||||
.Setup(s => s.Create(It.IsAny<Type>()))
|
||||
.Returns(() => stringLocalizer.Object);
|
||||
var provider = new DataAnnotationsMetadataProvider(stringLocalizerFactory.Object);
|
||||
|
||||
var display = new DisplayAttribute()
|
||||
{
|
||||
#if USE_REAL_RESOURCES
|
||||
Prompt = nameof(Test.Resources.DisplayAttribute_Prompt),
|
||||
ResourceType = typeof(Test.Resources),
|
||||
#else
|
||||
Prompt = nameof(DataAnnotations.Test.Resources.DisplayAttribute_Prompt),
|
||||
ResourceType = typeof(TestResources),
|
||||
#endif
|
||||
};
|
||||
|
||||
var attributes = new Attribute[] { display };
|
||||
var key = ModelMetadataIdentity.ForType(typeof(string));
|
||||
var context = new DisplayMetadataProviderContext(key, new ModelAttributes(attributes));
|
||||
|
||||
// Act
|
||||
provider.CreateDisplayMetadata(context);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("prompt from resources", context.DisplayMetadata.Placeholder());
|
||||
}
|
||||
|
||||
// This is IMPORTANT. Product code needs to use GetPrompt() instead of .Prompt. It's easy to regress.
|
||||
[Fact]
|
||||
public void CreateDisplayMetadata_DisplayAttribute_PromptFromResources_NullLocalizer()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsMetadataProvider(stringLocalizerFactory: null);
|
||||
|
||||
var display = new DisplayAttribute()
|
||||
{
|
||||
#if USE_REAL_RESOURCES
|
||||
Prompt = nameof(Test.Resources.DisplayAttribute_Prompt),
|
||||
ResourceType = typeof(Test.Resources),
|
||||
#else
|
||||
Prompt = nameof(DataAnnotations.Test.Resources.DisplayAttribute_Prompt),
|
||||
ResourceType = typeof(TestResources),
|
||||
#endif
|
||||
};
|
||||
|
||||
var attributes = new Attribute[] { display };
|
||||
var key = ModelMetadataIdentity.ForType(typeof(string));
|
||||
var context = new DisplayMetadataProviderContext(key, new ModelAttributes(attributes));
|
||||
|
||||
// Act
|
||||
provider.CreateDisplayMetadata(context);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("prompt from resources", context.DisplayMetadata.Placeholder());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateDisplayMetadata_DisplayAttribute_LocalizeProperties()
|
||||
{
|
||||
// Arrange
|
||||
var stringLocalizer = new Mock<IStringLocalizer>(MockBehavior.Strict);
|
||||
stringLocalizer
|
||||
.Setup(s => s["Model_Name"])
|
||||
.Returns(new LocalizedString("Model_Name", "name from localizer"));
|
||||
stringLocalizer
|
||||
.Setup(s => s["Model_Description"])
|
||||
.Returns(new LocalizedString("Model_Description", "description from localizer"));
|
||||
stringLocalizer
|
||||
.Setup(s => s["Model_Prompt"])
|
||||
.Returns(new LocalizedString("Model_Prompt", "prompt from localizer"));
|
||||
|
||||
var stringLocalizerFactory = new Mock<IStringLocalizerFactory>(MockBehavior.Strict);
|
||||
stringLocalizerFactory
|
||||
.Setup(f => f.Create(It.IsAny<Type>()))
|
||||
.Returns(stringLocalizer.Object);
|
||||
|
||||
var provider = new DataAnnotationsMetadataProvider(stringLocalizerFactory.Object);
|
||||
|
||||
var display = new DisplayAttribute()
|
||||
{
|
||||
Name = "Model_Name",
|
||||
Description = "Model_Description",
|
||||
Prompt = "Model_Prompt"
|
||||
};
|
||||
|
||||
var attributes = new Attribute[] { display };
|
||||
var key = ModelMetadataIdentity.ForType(typeof(DataAnnotationsMetadataProviderTest));
|
||||
var context = new DisplayMetadataProviderContext(key, new ModelAttributes(attributes));
|
||||
|
||||
// Act
|
||||
provider.CreateDisplayMetadata(context);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("name from localizer", context.DisplayMetadata.DisplayName());
|
||||
Assert.Equal("description from localizer", context.DisplayMetadata.Description());
|
||||
Assert.Equal("prompt from localizer", context.DisplayMetadata.Placeholder());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(typeof(EmptyClass), false)]
|
||||
[InlineData(typeof(ClassWithFields), false)]
|
||||
|
|
@ -232,7 +409,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
|||
public void CreateDisplayMetadata_IsEnum_ReflectsModelType(Type type, bool expectedIsEnum)
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsMetadataProvider();
|
||||
var provider = new DataAnnotationsMetadataProvider(stringLocalizerFactory: null);
|
||||
|
||||
var key = ModelMetadataIdentity.ForType(type);
|
||||
var attributes = new object[0];
|
||||
|
|
@ -266,7 +443,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
|||
public void CreateDisplayMetadata_IsFlagsEnum_ReflectsModelType(Type type, bool expectedIsFlagsEnum)
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsMetadataProvider();
|
||||
var provider = new DataAnnotationsMetadataProvider(stringLocalizerFactory: null);
|
||||
|
||||
var key = ModelMetadataIdentity.ForType(type);
|
||||
var attributes = new object[0];
|
||||
|
|
@ -398,7 +575,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
|||
IReadOnlyDictionary<string, string> expectedDictionary)
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsMetadataProvider();
|
||||
var provider = new DataAnnotationsMetadataProvider(stringLocalizerFactory: null);
|
||||
|
||||
var key = ModelMetadataIdentity.ForType(type);
|
||||
var attributes = new object[0];
|
||||
|
|
@ -532,7 +709,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
|||
IEnumerable<KeyValuePair<EnumGroupAndName, string>> expectedKeyValuePairs)
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsMetadataProvider();
|
||||
var provider = new DataAnnotationsMetadataProvider(stringLocalizerFactory: null);
|
||||
|
||||
var key = ModelMetadataIdentity.ForType(type);
|
||||
var attributes = new object[0];
|
||||
|
|
@ -554,7 +731,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
|||
public void CreateValidationMetadata_RequiredAttribute_SetsIsRequiredToTrue()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsMetadataProvider();
|
||||
var provider = new DataAnnotationsMetadataProvider(stringLocalizerFactory: null);
|
||||
|
||||
var required = new RequiredAttribute();
|
||||
|
||||
|
|
@ -576,7 +753,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
|||
public void CreateValidationMetadata_NoRequiredAttribute_IsRequiredLeftAlone(bool? initialValue)
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsMetadataProvider();
|
||||
var provider = new DataAnnotationsMetadataProvider(stringLocalizerFactory: null);
|
||||
|
||||
var attributes = new Attribute[] { };
|
||||
var key = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string));
|
||||
|
|
@ -597,7 +774,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
|||
public void CreateBindingMetadata_RequiredAttribute_IsBindingRequiredLeftAlone(bool initialValue)
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsMetadataProvider();
|
||||
var provider = new DataAnnotationsMetadataProvider(stringLocalizerFactory: null);
|
||||
|
||||
var attributes = new Attribute[] { new RequiredAttribute() };
|
||||
var key = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string));
|
||||
|
|
@ -618,7 +795,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
|||
public void CreateBindingDetails_NoEditableAttribute_IsReadOnlyLeftAlone(bool? initialValue)
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsMetadataProvider();
|
||||
var provider = new DataAnnotationsMetadataProvider(stringLocalizerFactory: null);
|
||||
|
||||
var attributes = new Attribute[] { };
|
||||
var key = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string));
|
||||
|
|
@ -636,7 +813,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
|||
public void CreateValidationDetails_ValidatableObject_ReturnsObject()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsMetadataProvider();
|
||||
var provider = new DataAnnotationsMetadataProvider(stringLocalizerFactory: null);
|
||||
|
||||
var attribute = new TestValidationAttribute();
|
||||
var attributes = new Attribute[] { attribute };
|
||||
|
|
@ -655,7 +832,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
|||
public void CreateValidationDetails_ValidatableObject_AlreadyInContext_Ignores()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsMetadataProvider();
|
||||
var provider = new DataAnnotationsMetadataProvider(stringLocalizerFactory: null);
|
||||
|
||||
var attribute = new TestValidationAttribute();
|
||||
var attributes = new Attribute[] { attribute };
|
||||
|
|
|
|||
|
|
@ -1050,7 +1050,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
|
|||
new DefaultCompositeMetadataDetailsProvider(new IMetadataDetailsProvider[]
|
||||
{
|
||||
new DefaultBindingMetadataProvider(),
|
||||
new DataAnnotationsMetadataProvider(),
|
||||
new DataAnnotationsMetadataProvider(stringLocalizerFactory: null),
|
||||
}),
|
||||
new TestOptionsManager<MvcOptions>())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
|
||||
public static string DisplayAttribute_Name { get; } = Resources.DisplayAttribute_Name;
|
||||
|
||||
public static string DisplayAttribute_Prompt { get; } = Resources.DisplayAttribute_Prompt;
|
||||
|
||||
public static string DisplayAttribute_CultureSensitiveName =>
|
||||
Resources.DisplayAttribute_Name + CultureInfo.CurrentUICulture;
|
||||
|
||||
|
|
|
|||
|
|
@ -58,6 +58,22 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Test
|
|||
return GetString("DisplayAttribute_Name");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// prompt from resources
|
||||
/// </summary>
|
||||
internal static string DisplayAttribute_Prompt
|
||||
{
|
||||
get { return GetString("DisplayAttribute_Prompt"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// prompt from resources
|
||||
/// </summary>
|
||||
internal static string FormatDisplayAttribute_Prompt()
|
||||
{
|
||||
return GetString("DisplayAttribute_Prompt");
|
||||
}
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
|
|
|
|||
|
|
@ -126,4 +126,7 @@
|
|||
<data name="DisplayAttribute_Name" xml:space="preserve">
|
||||
<value>name from resources</value>
|
||||
</data>
|
||||
<data name="DisplayAttribute_Prompt" xml:space="preserve">
|
||||
<value>prompt from resources</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
{
|
||||
new DefaultBindingMetadataProvider(),
|
||||
new DefaultValidationMetadataProvider(),
|
||||
new DataAnnotationsMetadataProvider(),
|
||||
new DataAnnotationsMetadataProvider(stringLocalizerFactory: null),
|
||||
new DataMemberRequiredBindingMetadataProvider(),
|
||||
};
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
{
|
||||
new DefaultBindingMetadataProvider(),
|
||||
new DefaultValidationMetadataProvider(),
|
||||
new DataAnnotationsMetadataProvider(),
|
||||
new DataAnnotationsMetadataProvider(stringLocalizerFactory: null),
|
||||
new DataMemberRequiredBindingMetadataProvider(),
|
||||
};
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
{
|
||||
new DefaultBindingMetadataProvider(),
|
||||
new DefaultValidationMetadataProvider(),
|
||||
new DataAnnotationsMetadataProvider(),
|
||||
new DataAnnotationsMetadataProvider(stringLocalizerFactory: null),
|
||||
detailsProvider
|
||||
}),
|
||||
new TestOptionsManager<MvcOptions>())
|
||||
|
|
|
|||
Loading…
Reference in New Issue