[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.
|
||||
/// </summary>
|
||||
[DebuggerDisplay("{DebuggerToString(),nq}")]
|
||||
public abstract class ModelMetadata : IEquatable<ModelMetadata>
|
||||
public abstract class ModelMetadata : IEquatable<ModelMetadata>, IModelMetadataProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// The default value of <see cref="ModelMetadata.Order"/>.
|
||||
|
|
@ -42,6 +42,17 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
/// </summary>
|
||||
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>
|
||||
/// Gets a value indicating the kind of metadata element represented by the current instance.
|
||||
/// </summary>
|
||||
|
|
@ -474,5 +485,17 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
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"/>
|
||||
/// </summary>
|
||||
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>
|
||||
/// Gets the <see cref="Metadata.BindingMetadata"/> for the current instance.
|
||||
/// </summary>
|
||||
|
|
@ -597,5 +606,17 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
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];
|
||||
for (var i = 0; i < properties.Length; i++)
|
||||
{
|
||||
propertyDetails[i].ContainerMetadata = cacheEntry.Metadata;
|
||||
properties[i] = CreateModelMetadata(propertyDetails[i]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -302,6 +302,36 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
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 string _displayName;
|
||||
|
|
|
|||
|
|
@ -57,6 +57,33 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
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]
|
||||
public void GetMetadataForProperties_IncludesAllProperties()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -744,6 +744,46 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
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)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue