ReadOnly attributes for Action, Controller, and Parameter
This commit is contained in:
parent
38b3b61485
commit
7b58d569eb
|
|
@ -9,12 +9,13 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||||
{
|
{
|
||||||
public class ActionModel
|
public class ActionModel
|
||||||
{
|
{
|
||||||
public ActionModel([NotNull] MethodInfo actionMethod)
|
public ActionModel([NotNull] MethodInfo actionMethod,
|
||||||
|
[NotNull] IReadOnlyList<object> attributes)
|
||||||
{
|
{
|
||||||
ActionMethod = actionMethod;
|
ActionMethod = actionMethod;
|
||||||
|
|
||||||
ApiExplorer = new ApiExplorerModel();
|
ApiExplorer = new ApiExplorerModel();
|
||||||
Attributes = new List<object>();
|
Attributes = new List<object>(attributes);
|
||||||
ActionConstraints = new List<IActionConstraintMetadata>();
|
ActionConstraints = new List<IActionConstraintMetadata>();
|
||||||
Filters = new List<IFilter>();
|
Filters = new List<IFilter>();
|
||||||
HttpMethods = new List<string>();
|
HttpMethods = new List<string>();
|
||||||
|
|
@ -45,9 +46,10 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||||
AttributeRouteModel = new AttributeRouteModel(other.AttributeRouteModel);
|
AttributeRouteModel = new AttributeRouteModel(other.AttributeRouteModel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<IActionConstraintMetadata> ActionConstraints { get; private set; }
|
public List<IActionConstraintMetadata> ActionConstraints { get; private set; }
|
||||||
|
|
||||||
public MethodInfo ActionMethod { get; private set; }
|
public MethodInfo ActionMethod { get; }
|
||||||
|
|
||||||
public string ActionName { get; set; }
|
public string ActionName { get; set; }
|
||||||
|
|
||||||
|
|
@ -60,7 +62,7 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public ApiExplorerModel ApiExplorer { get; set; }
|
public ApiExplorerModel ApiExplorer { get; set; }
|
||||||
|
|
||||||
public List<object> Attributes { get; private set; }
|
public IReadOnlyList<object> Attributes { get; }
|
||||||
|
|
||||||
public ControllerModel Controller { get; set; }
|
public ControllerModel Controller { get; set; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,14 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||||
{
|
{
|
||||||
public class ControllerModel
|
public class ControllerModel
|
||||||
{
|
{
|
||||||
public ControllerModel([NotNull] TypeInfo controllerType)
|
public ControllerModel([NotNull] TypeInfo controllerType,
|
||||||
|
[NotNull] IReadOnlyList<object> attributes)
|
||||||
{
|
{
|
||||||
ControllerType = controllerType;
|
ControllerType = controllerType;
|
||||||
|
|
||||||
Actions = new List<ActionModel>();
|
Actions = new List<ActionModel>();
|
||||||
ApiExplorer = new ApiExplorerModel();
|
ApiExplorer = new ApiExplorerModel();
|
||||||
Attributes = new List<object>();
|
Attributes = new List<object>(attributes);
|
||||||
AttributeRoutes = new List<AttributeRouteModel>();
|
AttributeRoutes = new List<AttributeRouteModel>();
|
||||||
ActionConstraints = new List<IActionConstraintMetadata>();
|
ActionConstraints = new List<IActionConstraintMetadata>();
|
||||||
Filters = new List<IFilter>();
|
Filters = new List<IFilter>();
|
||||||
|
|
@ -56,7 +57,7 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||||
|
|
||||||
public List<AttributeRouteModel> AttributeRoutes { get; private set; }
|
public List<AttributeRouteModel> AttributeRoutes { get; private set; }
|
||||||
|
|
||||||
public List<object> Attributes { get; private set; }
|
public IReadOnlyList<object> Attributes { get; }
|
||||||
|
|
||||||
public string ControllerName { get; set; }
|
public string ControllerName { get; set; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -213,13 +213,11 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||||
[NotNull] MethodInfo methodInfo,
|
[NotNull] MethodInfo methodInfo,
|
||||||
[NotNull] IReadOnlyList<object> attributes)
|
[NotNull] IReadOnlyList<object> attributes)
|
||||||
{
|
{
|
||||||
var actionModel = new ActionModel(methodInfo)
|
var actionModel = new ActionModel(methodInfo, attributes)
|
||||||
{
|
{
|
||||||
IsActionNameMatchRequired = true,
|
IsActionNameMatchRequired = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
actionModel.Attributes.AddRange(attributes);
|
|
||||||
|
|
||||||
actionModel.ActionConstraints.AddRange(attributes.OfType<IActionConstraintMetadata>());
|
actionModel.ActionConstraints.AddRange(attributes.OfType<IActionConstraintMetadata>());
|
||||||
actionModel.Filters.AddRange(attributes.OfType<IFilter>());
|
actionModel.Filters.AddRange(attributes.OfType<IFilter>());
|
||||||
|
|
||||||
|
|
@ -268,12 +266,10 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||||
/// <returns>A <see cref="ParameterModel"/> for the given <see cref="ParameterInfo"/>.</returns>
|
/// <returns>A <see cref="ParameterModel"/> for the given <see cref="ParameterInfo"/>.</returns>
|
||||||
protected virtual ParameterModel CreateParameterModel([NotNull] ParameterInfo parameterInfo)
|
protected virtual ParameterModel CreateParameterModel([NotNull] ParameterInfo parameterInfo)
|
||||||
{
|
{
|
||||||
var parameterModel = new ParameterModel(parameterInfo);
|
|
||||||
|
|
||||||
// CoreCLR returns IEnumerable<Attribute> from GetCustomAttributes - the OfType<object>
|
// CoreCLR returns IEnumerable<Attribute> from GetCustomAttributes - the OfType<object>
|
||||||
// is needed to so that the result of ToArray() is object
|
// is needed to so that the result of ToArray() is object
|
||||||
var attributes = parameterInfo.GetCustomAttributes(inherit: true).OfType<object>().ToArray();
|
var attributes = parameterInfo.GetCustomAttributes(inherit: true).OfType<object>().ToArray();
|
||||||
parameterModel.Attributes.AddRange(attributes);
|
var parameterModel = new ParameterModel(parameterInfo, attributes);
|
||||||
|
|
||||||
parameterModel.BinderMetadata = attributes.OfType<IBinderMetadata>().FirstOrDefault();
|
parameterModel.BinderMetadata = attributes.OfType<IBinderMetadata>().FirstOrDefault();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,12 +88,10 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||||
/// <returns>A <see cref="ControllerModel"/> for the given <see cref="TypeInfo"/>.</returns>
|
/// <returns>A <see cref="ControllerModel"/> for the given <see cref="TypeInfo"/>.</returns>
|
||||||
protected virtual ControllerModel CreateControllerModel([NotNull] TypeInfo typeInfo)
|
protected virtual ControllerModel CreateControllerModel([NotNull] TypeInfo typeInfo)
|
||||||
{
|
{
|
||||||
var controllerModel = new ControllerModel(typeInfo);
|
|
||||||
|
|
||||||
// CoreCLR returns IEnumerable<Attribute> from GetCustomAttributes - the OfType<object>
|
// CoreCLR returns IEnumerable<Attribute> from GetCustomAttributes - the OfType<object>
|
||||||
// is needed to so that the result of ToArray() is object
|
// is needed to so that the result of ToArray() is object
|
||||||
var attributes = typeInfo.GetCustomAttributes(inherit: true).OfType<object>().ToArray();
|
var attributes = typeInfo.GetCustomAttributes(inherit: true).OfType<object>().ToArray();
|
||||||
controllerModel.Attributes.AddRange(attributes);
|
var controllerModel = new ControllerModel(typeInfo, attributes);
|
||||||
|
|
||||||
controllerModel.ControllerName =
|
controllerModel.ControllerName =
|
||||||
typeInfo.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase) ?
|
typeInfo.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase) ?
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,12 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||||
{
|
{
|
||||||
public class ParameterModel
|
public class ParameterModel
|
||||||
{
|
{
|
||||||
public ParameterModel(ParameterInfo parameterInfo)
|
public ParameterModel(ParameterInfo parameterInfo,
|
||||||
|
IReadOnlyList<object> attributes)
|
||||||
{
|
{
|
||||||
ParameterInfo = parameterInfo;
|
ParameterInfo = parameterInfo;
|
||||||
|
|
||||||
Attributes = new List<object>();
|
Attributes = new List<object>(attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ParameterModel([NotNull] ParameterModel other)
|
public ParameterModel([NotNull] ParameterModel other)
|
||||||
|
|
@ -28,7 +29,7 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||||
|
|
||||||
public ActionModel Action { get; set; }
|
public ActionModel Action { get; set; }
|
||||||
|
|
||||||
public List<object> Attributes { get; private set; }
|
public IReadOnlyList<object> Attributes { get; }
|
||||||
|
|
||||||
public IBinderMetadata BinderMetadata { get; set; }
|
public IBinderMetadata BinderMetadata { get; set; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,11 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||||
public void CopyConstructor_DoesDeepCopyOfOtherModels()
|
public void CopyConstructor_DoesDeepCopyOfOtherModels()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var action = new ActionModel(typeof(TestController).GetMethod("Edit"));
|
var action = new ActionModel(typeof(TestController).GetMethod("Edit"),
|
||||||
|
new List<object>());
|
||||||
|
|
||||||
var parameter = new ParameterModel(action.ActionMethod.GetParameters()[0]);
|
var parameter = new ParameterModel(action.ActionMethod.GetParameters()[0],
|
||||||
|
new List<object>());
|
||||||
parameter.Action = action;
|
parameter.Action = action;
|
||||||
action.Parameters.Add(parameter);
|
action.Parameters.Add(parameter);
|
||||||
|
|
||||||
|
|
@ -40,13 +42,14 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||||
public void CopyConstructor_CopiesAllProperties()
|
public void CopyConstructor_CopiesAllProperties()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var action = new ActionModel(typeof(TestController).GetMethod("Edit"));
|
var action = new ActionModel(typeof(TestController).GetMethod("Edit"),
|
||||||
|
new List<object>() { new HttpGetAttribute() });
|
||||||
|
|
||||||
action.ActionConstraints.Add(new HttpMethodConstraint(new string[] { "GET" }));
|
action.ActionConstraints.Add(new HttpMethodConstraint(new string[] { "GET" }));
|
||||||
action.ActionName = "Edit";
|
action.ActionName = "Edit";
|
||||||
|
|
||||||
action.Attributes.Add(new HttpGetAttribute());
|
action.Controller = new ControllerModel(typeof(TestController).GetTypeInfo(),
|
||||||
action.Controller = new ControllerModel(typeof(TestController).GetTypeInfo());
|
new List<object>());
|
||||||
action.Filters.Add(new AuthorizeAttribute());
|
action.Filters.Add(new AuthorizeAttribute());
|
||||||
action.HttpMethods.Add("GET");
|
action.HttpMethods.Add("GET");
|
||||||
action.IsActionNameMatchRequired = true;
|
action.IsActionNameMatchRequired = true;
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,11 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||||
public void CopyConstructor_DoesDeepCopyOfOtherModels()
|
public void CopyConstructor_DoesDeepCopyOfOtherModels()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var controller = new ControllerModel(typeof(TestController).GetTypeInfo());
|
var controller = new ControllerModel(typeof(TestController).GetTypeInfo(),
|
||||||
|
new List<object>());
|
||||||
|
|
||||||
var action = new ActionModel(typeof(TestController).GetMethod("Edit"));
|
var action = new ActionModel(typeof(TestController).GetMethod("Edit"),
|
||||||
|
new List<object>());
|
||||||
controller.Actions.Add(action);
|
controller.Actions.Add(action);
|
||||||
action.Controller = controller;
|
action.Controller = controller;
|
||||||
|
|
||||||
|
|
@ -46,11 +48,11 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||||
public void CopyConstructor_CopiesAllProperties()
|
public void CopyConstructor_CopiesAllProperties()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var controller = new ControllerModel(typeof(TestController).GetTypeInfo());
|
var controller = new ControllerModel(typeof(TestController).GetTypeInfo(),
|
||||||
|
new List<object>() { new HttpGetAttribute() });
|
||||||
|
|
||||||
controller.ActionConstraints.Add(new HttpMethodConstraint(new string[] { "GET" }));
|
controller.ActionConstraints.Add(new HttpMethodConstraint(new string[] { "GET" }));
|
||||||
controller.Application = new ApplicationModel();
|
controller.Application = new ApplicationModel();
|
||||||
controller.Attributes.Add(new HttpGetAttribute());
|
|
||||||
controller.ControllerName = "cool";
|
controller.ControllerName = "cool";
|
||||||
controller.Filters.Add(new AuthorizeAttribute());
|
controller.Filters.Add(new AuthorizeAttribute());
|
||||||
controller.RouteConstraints.Add(new AreaAttribute("Admin"));
|
controller.RouteConstraints.Add(new AreaAttribute("Admin"));
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,10 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||||
public void CopyConstructor_CopiesAllProperties()
|
public void CopyConstructor_CopiesAllProperties()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var parameter = new ParameterModel(typeof(TestController).GetMethod("Edit").GetParameters()[0]);
|
var parameter = new ParameterModel(typeof(TestController).GetMethod("Edit").GetParameters()[0],
|
||||||
|
new List<object>() { new FromBodyAttribute() });
|
||||||
|
|
||||||
parameter.Action = new ActionModel(typeof(TestController).GetMethod("Edit"));
|
parameter.Action = new ActionModel(typeof(TestController).GetMethod("Edit"), new List<object>());
|
||||||
parameter.Attributes.Add(new FromBodyAttribute());
|
|
||||||
parameter.BinderMetadata = (IBinderMetadata)parameter.Attributes[0];
|
parameter.BinderMetadata = (IBinderMetadata)parameter.Attributes[0];
|
||||||
parameter.IsOptional = true;
|
parameter.IsOptional = true;
|
||||||
parameter.ParameterName = "id";
|
parameter.ParameterName = "id";
|
||||||
|
|
|
||||||
|
|
@ -1136,19 +1136,25 @@ namespace Microsoft.AspNet.Mvc.Test
|
||||||
|
|
||||||
var options = new MockMvcOptionsAccessor();
|
var options = new MockMvcOptionsAccessor();
|
||||||
options.Options.ApplicationModelConventions.Add(applicationConvention.Object);
|
options.Options.ApplicationModelConventions.Add(applicationConvention.Object);
|
||||||
|
|
||||||
var provider = GetProvider(typeof(ConventionsController).GetTypeInfo(), options);
|
var provider = GetProvider(typeof(ConventionsController).GetTypeInfo(), options);
|
||||||
|
|
||||||
var model = provider.BuildModel();
|
var model = provider.BuildModel();
|
||||||
|
|
||||||
var controller = model.Controllers.Single();
|
var controller = model.Controllers.Single();
|
||||||
controller.Attributes.Add(controllerConvention.Object);
|
model.Controllers.Remove(controller);
|
||||||
|
controller = BuildControllerModel(controller, controllerConvention.Object);
|
||||||
|
model.Controllers.Add(controller);
|
||||||
|
|
||||||
var action = controller.Actions.Single();
|
var action = controller.Actions.Single();
|
||||||
action.Attributes.Add(actionConvention.Object);
|
controller.Actions.Remove(action);
|
||||||
|
action = BuildActionModel(action, actionConvention.Object);
|
||||||
|
controller.Actions.Add(action);
|
||||||
|
|
||||||
var parameter = action.Parameters.Single();
|
var parameter = action.Parameters.Single();
|
||||||
parameter.Attributes.Add(parameterConvention.Object);
|
action.Parameters.Remove(parameter);
|
||||||
|
parameter = BuildParameterModel(parameter, parameterConvention.Object);
|
||||||
|
action.Parameters.Add(parameter);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
ApplicationModelConventions.ApplyConventions(model, options.Options.ApplicationModelConventions);
|
ApplicationModelConventions.ApplyConventions(model, options.Options.ApplicationModelConventions);
|
||||||
|
|
@ -1300,6 +1306,33 @@ namespace Microsoft.AspNet.Mvc.Test
|
||||||
Assert.Single(action.ActionConstraints, a => a is ConstraintAttribute);
|
Assert.Single(action.ActionConstraints, a => a is ConstraintAttribute);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ActionModel BuildActionModel(ActionModel action, IActionModelConvention actionConvention)
|
||||||
|
{
|
||||||
|
var t = new ActionModel(action.ActionMethod,
|
||||||
|
new List<object>(action.Attributes) { actionConvention });
|
||||||
|
t.Parameters.AddRange(action.Parameters);
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ParameterModel BuildParameterModel(ParameterModel parameter, IParameterModelConvention parameterConvention)
|
||||||
|
{
|
||||||
|
var t = new ParameterModel(parameter.ParameterInfo,
|
||||||
|
new List<object>(parameter.Attributes) { parameterConvention });
|
||||||
|
t.Action = parameter.Action;
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ControllerModel BuildControllerModel(ControllerModel controller, IControllerModelConvention controllerConvention)
|
||||||
|
{
|
||||||
|
var t = new ControllerModel(controller.ControllerType,
|
||||||
|
new List<object>(controller.Attributes) { controllerConvention });
|
||||||
|
t.Actions.AddRange(controller.Actions);
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
private ControllerActionDescriptorProvider GetProvider(
|
private ControllerActionDescriptorProvider GetProvider(
|
||||||
TypeInfo controllerTypeInfo,
|
TypeInfo controllerTypeInfo,
|
||||||
IEnumerable<IFilter> filters = null)
|
IEnumerable<IFilter> filters = null)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue