Adds common interfaces around Models (Implements #3158)

This commit is contained in:
Nero Sule 2015-09-23 10:03:37 +01:00 committed by Ryan Nowak
parent 9c81b95d1b
commit 49acfd562e
13 changed files with 145 additions and 9 deletions

View File

@ -12,6 +12,30 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
/// </summary>
public class BindingInfo
{
/// <summary>
/// Creates a new <see cref="BindingInfo"/>.
/// </summary>
public BindingInfo()
{
}
/// <summary>
/// Creates a copy of a <see cref="BindingInfo"/>.
/// </summary>
/// <param name="other">The <see cref="BindingInfo"/> to copy.</param>
public BindingInfo(BindingInfo other)
{
if (other == null)
{
throw new ArgumentNullException(nameof(other));
}
BindingSource = other.BindingSource;
BinderModelName = other.BinderModelName;
BinderType = other.BinderType;
PropertyBindingPredicateProvider = other.PropertyBindingPredicateProvider;
}
/// <summary>
/// Gets or sets the <see cref="ModelBinding.BindingSource"/>.
/// </summary>

View File

@ -14,7 +14,7 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
{
[DebuggerDisplay("Name={ActionName}({Methods()}), Type={Controller.ControllerType.Name}," +
" Route: {AttributeRouteModel?.Template}, Filters: {Filters.Count}")]
public class ActionModel
public class ActionModel : ICommonModel, IFilterModel, IApiExplorerModel
{
public ActionModel(
[NotNull] MethodInfo actionMethod,
@ -100,6 +100,10 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
/// </remarks>
public IDictionary<object, object> Properties { get; }
MemberInfo ICommonModel.MemberInfo => ActionMethod;
string ICommonModel.Name => ActionName;
private string Methods()
{
if (HttpMethods.Count == 0)

View File

@ -8,7 +8,7 @@ using Microsoft.AspNet.Mvc.Filters;
namespace Microsoft.AspNet.Mvc.ApplicationModels
{
[DebuggerDisplay("ApplicationModel: Controllers: {Controllers.Count}, Filters: {Filters.Count}")]
public class ApplicationModel
public class ApplicationModel : IPropertyModel, IFilterModel, IApiExplorerModel
{
public ApplicationModel()
{

View File

@ -14,7 +14,7 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
{
[DebuggerDisplay("Name={ControllerName}, Type={ControllerType.Name}," +
" Routes: {AttributeRoutes.Count}, Filters: {Filters.Count}")]
public class ControllerModel
public class ControllerModel : ICommonModel, IFilterModel, IApiExplorerModel
{
public ControllerModel(
[NotNull] TypeInfo controllerType,
@ -79,6 +79,10 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
public IReadOnlyList<object> Attributes { get; }
MemberInfo ICommonModel.MemberInfo => ControllerType;
string ICommonModel.Name => ControllerName;
public string ControllerName { get; set; }
public TypeInfo ControllerType { get; private set; }

View File

@ -0,0 +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.
namespace Microsoft.AspNet.Mvc.ApplicationModels
{
public interface IApiExplorerModel
{
ApiExplorerModel ApiExplorer { get; set; }
}
}

View File

@ -0,0 +1,12 @@
// 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 Microsoft.AspNet.Mvc.ModelBinding;
namespace Microsoft.AspNet.Mvc.ApplicationModels
{
public interface IBindingModel
{
BindingInfo BindingInfo { get; set; }
}
}

View File

@ -0,0 +1,15 @@
// 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.Collections.Generic;
using System.Reflection;
namespace Microsoft.AspNet.Mvc.ApplicationModels
{
public interface ICommonModel : IPropertyModel
{
IReadOnlyList<object> Attributes { get; }
MemberInfo MemberInfo { get; }
string Name { get; }
}
}

View File

@ -0,0 +1,13 @@
// 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.Collections.Generic;
using Microsoft.AspNet.Mvc.Filters;
namespace Microsoft.AspNet.Mvc.ApplicationModels
{
public interface IFilterModel
{
IList<IFilterMetadata> Filters { get; }
}
}

View File

@ -0,0 +1,12 @@
// 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.Collections.Generic;
namespace Microsoft.AspNet.Mvc.ApplicationModels
{
public interface IPropertyModel
{
IDictionary<object, object> Properties { get; }
}
}

View File

@ -10,14 +10,14 @@ using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Mvc.ApplicationModels
{
[DebuggerDisplay("ParameterModel: Name={ParameterName}")]
public class ParameterModel
public class ParameterModel : ICommonModel, IBindingModel
{
public ParameterModel(
[NotNull] ParameterInfo parameterInfo,
[NotNull] IReadOnlyList<object> attributes)
{
ParameterInfo = parameterInfo;
Properties = new Dictionary<object, object>();
Attributes = new List<object>(attributes);
}
@ -25,15 +25,22 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
{
Action = other.Action;
Attributes = new List<object>(other.Attributes);
BindingInfo = other.BindingInfo;
BindingInfo = other.BindingInfo == null ? null : new BindingInfo(other.BindingInfo);
ParameterInfo = other.ParameterInfo;
ParameterName = other.ParameterName;
Properties = new Dictionary<object, object>(other.Properties);
}
public ActionModel Action { get; set; }
public IReadOnlyList<object> Attributes { get; }
public IDictionary<object, object> Properties { get; }
MemberInfo ICommonModel.MemberInfo => ParameterInfo.Member;
string ICommonModel.Name => ParameterName;
public ParameterInfo ParameterInfo { get; private set; }
public string ParameterName { get; set; }

View File

@ -13,7 +13,7 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
/// A type which is used to represent a property in a <see cref="ControllerModel"/>.
/// </summary>
[DebuggerDisplay("PropertyModel: Name={PropertyName}")]
public class PropertyModel
public class PropertyModel : ICommonModel, IBindingModel
{
/// <summary>
/// Creates a new instance of <see cref="PropertyModel"/>.
@ -25,7 +25,7 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
[NotNull] IReadOnlyList<object> attributes)
{
PropertyInfo = propertyInfo;
Properties = new Dictionary<object, object>();
Attributes = new List<object>(attributes);
}
@ -37,9 +37,10 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
{
Controller = other.Controller;
Attributes = new List<object>(other.Attributes);
BindingInfo = other.BindingInfo;
BindingInfo = BindingInfo == null ? null : new BindingInfo(other.BindingInfo);
PropertyInfo = other.PropertyInfo;
PropertyName = other.PropertyName;
Properties = new Dictionary<object, object>(other.Properties);
}
/// <summary>
@ -52,6 +53,12 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
/// </summary>
public IReadOnlyList<object> Attributes { get; }
public IDictionary<object, object> Properties { get; }
MemberInfo ICommonModel.MemberInfo => PropertyInfo;
string ICommonModel.Name => PropertyName;
/// <summary>
/// Gets or sets the <see cref="BindingInfo"/> associated with this model.
/// </summary>

View File

@ -25,6 +25,7 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
};
parameter.ParameterName = "id";
parameter.Properties.Add(new KeyValuePair<object, object>("test key", "test value"));
// Act
var parameter2 = new ParameterModel(parameter);
@ -32,6 +33,12 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
// Assert
foreach (var property in typeof(ParameterModel).GetProperties())
{
if (property.Name.Equals("BindingInfo"))
{
// This test excludes other mutable objects on purpose because we deep copy them.
continue;
}
var value1 = property.GetValue(parameter);
var value2 = property.GetValue(parameter2);
@ -42,6 +49,13 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
// Ensure non-default value
Assert.NotEmpty((IEnumerable<object>)value1);
}
else if (typeof(IDictionary<object, object>).IsAssignableFrom(property.PropertyType))
{
Assert.Equal(value1, value2);
// Ensure non-default value
Assert.NotEmpty((IDictionary<object, object>)value1);
}
else if (property.PropertyType.IsValueType ||
Nullable.GetUnderlyingType(property.PropertyType) != null)
{

View File

@ -21,6 +21,7 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
propertyModel.Controller = new ControllerModel(typeof(TestController).GetTypeInfo(), new List<object>());
propertyModel.BindingInfo = BindingInfo.GetBindingInfo(propertyModel.Attributes);
propertyModel.PropertyName = "Property";
propertyModel.Properties.Add(new KeyValuePair<object, object>("test key", "test value"));
// Act
var propertyModel2 = new PropertyModel(propertyModel);
@ -28,6 +29,12 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
// Assert
foreach (var property in typeof(PropertyModel).GetProperties())
{
if (property.Name.Equals("BindingInfo"))
{
// This test excludes other mutable objects on purpose because we deep copy them.
continue;
}
var value1 = property.GetValue(propertyModel);
var value2 = property.GetValue(propertyModel2);
@ -38,6 +45,13 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
// Ensure non-default value
Assert.NotEmpty((IEnumerable<object>)value1);
}
else if (typeof(IDictionary<object, object>).IsAssignableFrom(property.PropertyType))
{
Assert.Equal(value1, value2);
// Ensure non-default value
Assert.NotEmpty((IDictionary<object, object>)value1);
}
else if (property.PropertyType.IsValueType ||
Nullable.GetUnderlyingType(property.PropertyType) != null)
{