[Fixes #5686] Extend `ModelMetadata` to reduce ugliness
This commit is contained in:
parent
4da7356348
commit
c95c2a5a6d
|
|
@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
/// A metadata representation of a model type, property or parameter.
|
/// A metadata representation of a model type, property or parameter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DebuggerDisplay("{DebuggerToString(),nq}")]
|
[DebuggerDisplay("{DebuggerToString(),nq}")]
|
||||||
public abstract class ModelMetadata : IEquatable<ModelMetadata>
|
public abstract class ModelMetadata : IEquatable<ModelMetadata>, IModelMetadataProvider
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The default value of <see cref="ModelMetadata.Order"/>.
|
/// The default value of <see cref="ModelMetadata.Order"/>.
|
||||||
|
|
@ -42,6 +42,17 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Type ContainerType { get { return Identity.ContainerType; } }
|
public Type ContainerType { get { return Identity.ContainerType; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the metadata of the container type that the current instance is part of.
|
||||||
|
/// </summary>
|
||||||
|
public virtual ModelMetadata ContainerMetadata
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating the kind of metadata element represented by the current instance.
|
/// Gets a value indicating the kind of metadata element represented by the current instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -474,5 +485,17 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
return $"ModelMetadata (Property: '{ContainerType.Name}.{PropertyName}' Type: '{ModelType.Name}')";
|
return $"ModelMetadata (Property: '{ContainerType.Name}.{PropertyName}' Type: '{ModelType.Name}')";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public virtual ModelMetadata GetMetadataForType(Type modelType)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public virtual IEnumerable<ModelMetadata> GetMetadataForProperties(Type modelType)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,5 +68,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
/// Gets or sets the <see cref="Metadata.ValidationMetadata"/>
|
/// Gets or sets the <see cref="Metadata.ValidationMetadata"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ValidationMetadata ValidationMetadata { get; set; }
|
public ValidationMetadata ValidationMetadata { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="ModelMetadata"/> of the container type.
|
||||||
|
/// </summary>
|
||||||
|
public ModelMetadata ContainerMetadata { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -96,6 +96,15 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override ModelMetadata ContainerMetadata
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _details.ContainerMetadata;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="Metadata.BindingMetadata"/> for the current instance.
|
/// Gets the <see cref="Metadata.BindingMetadata"/> for the current instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -597,5 +606,17 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
return _details.PropertySetter;
|
return _details.PropertySetter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override ModelMetadata GetMetadataForType(Type modelType)
|
||||||
|
{
|
||||||
|
return _provider.GetMetadataForType(modelType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override IEnumerable<ModelMetadata> GetMetadataForProperties(Type modelType)
|
||||||
|
{
|
||||||
|
return _provider.GetMetadataForProperties(modelType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -87,6 +87,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
var properties = new ModelMetadata[propertyDetails.Length];
|
var properties = new ModelMetadata[propertyDetails.Length];
|
||||||
for (var i = 0; i < properties.Length; i++)
|
for (var i = 0; i < properties.Length; i++)
|
||||||
{
|
{
|
||||||
|
propertyDetails[i].ContainerMetadata = cacheEntry.Metadata;
|
||||||
properties[i] = CreateModelMetadata(propertyDetails[i]);
|
properties[i] = CreateModelMetadata(propertyDetails[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -302,6 +302,36 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
Assert.Equal("String", result);
|
Assert.Equal("String", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetContainerMetadata_ThrowsNotImplementedException_ByDefault()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var metadata = new TestModelMetadata(typeof(DerivedList));
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
Assert.Throws<NotImplementedException>(() => metadata.ContainerMetadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetMetadataForType_ByDefaultThrows_NotImplementedException()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var metadata = new TestModelMetadata(typeof(string));
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
var result = Assert.Throws<NotImplementedException>(() => metadata.GetMetadataForType(typeof(string)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetMetadataForProperties_ByDefaultThrows_NotImplementedException()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var metadata = new TestModelMetadata(typeof(string));
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
var result = Assert.Throws<NotImplementedException>(() => metadata.GetMetadataForProperties(typeof(string)));
|
||||||
|
}
|
||||||
|
|
||||||
private class TestModelMetadata : ModelMetadata
|
private class TestModelMetadata : ModelMetadata
|
||||||
{
|
{
|
||||||
private string _displayName;
|
private string _displayName;
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,33 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
Assert.Same(metadata1, metadata2);
|
Assert.Same(metadata1, metadata2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetMetadataForProperties_IncludesContainerMetadataForAllProperties()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var provider = CreateProvider();
|
||||||
|
var modelType = typeof(ModelType);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var metadata = provider.GetMetadataForProperties(modelType).ToArray();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Collection(
|
||||||
|
metadata,
|
||||||
|
(propertyMetadata) =>
|
||||||
|
{
|
||||||
|
Assert.Equal("Property1", propertyMetadata.PropertyName);
|
||||||
|
Assert.NotNull(propertyMetadata.ContainerMetadata);
|
||||||
|
Assert.Equal(modelType, propertyMetadata.ContainerMetadata.ModelType);
|
||||||
|
},
|
||||||
|
(propertyMetadata) =>
|
||||||
|
{
|
||||||
|
Assert.Equal("Property2", propertyMetadata.PropertyName);
|
||||||
|
Assert.NotNull(propertyMetadata.ContainerMetadata);
|
||||||
|
Assert.Equal(modelType, propertyMetadata.ContainerMetadata.ModelType);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetMetadataForProperties_IncludesAllProperties()
|
public void GetMetadataForProperties_IncludesAllProperties()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -744,6 +744,46 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
||||||
Assert.False(validateChildren);
|
Assert.False(validateChildren);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetMetadataForType_CallsProvider()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var detailsProvider = new Mock<ICompositeMetadataDetailsProvider>();
|
||||||
|
var key = ModelMetadataIdentity.ForType(typeof(string));
|
||||||
|
var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0]));
|
||||||
|
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||||
|
metadataProvider
|
||||||
|
.Setup(mp => mp.GetMetadataForType(typeof(string)))
|
||||||
|
.Verifiable();
|
||||||
|
var metadata1 = new DefaultModelMetadata(metadataProvider.Object, detailsProvider.Object, cache);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var metadata2 = metadata1.GetMetadataForType(typeof(string));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
metadataProvider.VerifyAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetMetadataForProperties_CallsProvider()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var detailsProvider = new Mock<ICompositeMetadataDetailsProvider>();
|
||||||
|
var key = ModelMetadataIdentity.ForType(typeof(string));
|
||||||
|
var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0]));
|
||||||
|
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||||
|
metadataProvider
|
||||||
|
.Setup(mp => mp.GetMetadataForProperties(typeof(Exception)))
|
||||||
|
.Verifiable();
|
||||||
|
var metadata1 = new DefaultModelMetadata(metadataProvider.Object, detailsProvider.Object, cache);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var metadata2 = metadata1.GetMetadataForProperties(typeof(Exception));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
metadataProvider.VerifyAll();
|
||||||
|
}
|
||||||
|
|
||||||
private void ActionMethod(string input)
|
private void ActionMethod(string input)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue