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