Provided a way to add data to ActionDescriptor from ApplicationModel.
- Added Properties to Action, Controller and Application model - Added relevant tests
This commit is contained in:
parent
02f656667f
commit
8e85d53c88
|
|
@ -21,6 +21,7 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
|||
HttpMethods = new List<string>();
|
||||
Parameters = new List<ParameterModel>();
|
||||
RouteConstraints = new List<IRouteConstraintProvider>();
|
||||
Properties = new Dictionary<object, object>();
|
||||
}
|
||||
|
||||
public ActionModel([NotNull] ActionModel other)
|
||||
|
|
@ -36,6 +37,7 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
|||
Attributes = new List<object>(other.Attributes);
|
||||
Filters = new List<IFilter>(other.Filters);
|
||||
HttpMethods = new List<string>(other.HttpMethods);
|
||||
Properties = new Dictionary<object, object>(other.Properties);
|
||||
|
||||
// Make a deep copy of other 'model' types.
|
||||
ApiExplorer = new ApiExplorerModel(other.ApiExplorer);
|
||||
|
|
@ -79,5 +81,15 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
|||
public IList<ParameterModel> Parameters { get; private set; }
|
||||
|
||||
public IList<IRouteConstraintProvider> RouteConstraints { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a set of properties associated with the action.
|
||||
/// These properties will be copied to <see cref="ActionDescriptor.Properties"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Entries will take precedence over entries with the same key in
|
||||
/// <see cref="ApplicationModel.Properties"/> and <see cref="ControllerModel.Properties"/>.
|
||||
/// </remarks>
|
||||
public IDictionary<object, object> Properties { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
|||
ApiExplorer = new ApiExplorerModel();
|
||||
Controllers = new List<ControllerModel>();
|
||||
Filters = new List<IFilter>();
|
||||
Properties = new Dictionary<object, object>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -30,5 +31,11 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
|||
public IList<ControllerModel> Controllers { get; private set; }
|
||||
|
||||
public IList<IFilter> Filters { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a set of properties associated with all actions.
|
||||
/// These properties will be copied to <see cref="ActionDescriptor.Properties"/>.
|
||||
/// </summary>
|
||||
public IDictionary<object, object> Properties { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
|||
ActionConstraints = new List<IActionConstraintMetadata>();
|
||||
Filters = new List<IFilter>();
|
||||
RouteConstraints = new List<IRouteConstraintProvider>();
|
||||
Properties = new Dictionary<object, object>();
|
||||
}
|
||||
|
||||
public ControllerModel([NotNull] ControllerModel other)
|
||||
|
|
@ -36,6 +37,7 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
|||
Attributes = new List<object>(other.Attributes);
|
||||
Filters = new List<IFilter>(other.Filters);
|
||||
RouteConstraints = new List<IRouteConstraintProvider>(other.RouteConstraints);
|
||||
Properties = new Dictionary<object, object>(other.Properties);
|
||||
|
||||
// Make a deep copy of other 'model' types.
|
||||
Actions = new List<ActionModel>(other.Actions.Select(a => new ActionModel(a)));
|
||||
|
|
@ -73,5 +75,15 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
|||
public IList<IFilter> Filters { get; private set; }
|
||||
|
||||
public IList<IRouteConstraintProvider> RouteConstraints { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a set of properties associated with the controller.
|
||||
/// These properties will be copied to <see cref="ActionDescriptor.Properties"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Entries will take precedence over entries with the same key
|
||||
/// in <see cref="ApplicationModel.Properties"/>.
|
||||
/// </remarks>
|
||||
public IDictionary<object, object> Properties { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
AddApiExplorerInfo(actionDescriptor, application, controller, action);
|
||||
AddRouteConstraints(removalConstraints, actionDescriptor, controller, action);
|
||||
AddProperties(actionDescriptor, action, controller, application);
|
||||
|
||||
if (IsAttributeRoutedAction(actionDescriptor))
|
||||
{
|
||||
|
|
@ -329,6 +330,28 @@ namespace Microsoft.AspNet.Mvc
|
|||
}
|
||||
}
|
||||
|
||||
private static void AddProperties(
|
||||
ControllerActionDescriptor actionDescriptor,
|
||||
ActionModel action,
|
||||
ControllerModel controller,
|
||||
ApplicationModel application)
|
||||
{
|
||||
foreach (var item in application.Properties)
|
||||
{
|
||||
actionDescriptor.Properties[item.Key] = item.Value;
|
||||
}
|
||||
|
||||
foreach (var item in controller.Properties)
|
||||
{
|
||||
actionDescriptor.Properties[item.Key] = item.Value;
|
||||
}
|
||||
|
||||
foreach (var item in action.Properties)
|
||||
{
|
||||
actionDescriptor.Properties[item.Key] = item.Value;
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddActionFilters(
|
||||
ControllerActionDescriptor actionDescriptor,
|
||||
IEnumerable<IFilter> actionFilters,
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ namespace Microsoft.AspNet.Mvc.Logging
|
|||
}
|
||||
HttpMethods = inner.HttpMethods;
|
||||
ActionConstraints = inner.ActionConstraints?.Select(a => new ActionConstraintValues(a))?.ToList();
|
||||
Properties = new Dictionary<object, object>(inner.Properties);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -86,6 +87,11 @@ namespace Microsoft.AspNet.Mvc.Logging
|
|||
/// </summary>
|
||||
public IList<ActionConstraintValues> ActionConstraints { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the set of properties associated with the action <see cref="ActionModel.Properties"/>.
|
||||
/// </summary>
|
||||
public IDictionary<object, object> Properties { get; }
|
||||
|
||||
public override string Format()
|
||||
{
|
||||
return LogFormatter.FormatStructure(this);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ namespace Microsoft.AspNet.Mvc.Logging
|
|||
r => new RouteConstraintProviderValues(r)).ToList();
|
||||
AttributeRoutes = inner.AttributeRoutes.Select(
|
||||
a => new AttributeRouteModelValues(a)).ToList();
|
||||
Properties = new Dictionary<object, object>(inner.Properties);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -83,6 +84,11 @@ namespace Microsoft.AspNet.Mvc.Logging
|
|||
/// </summary>
|
||||
public List<AttributeRouteModelValues> AttributeRoutes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the set of properties associated with the controller <see cref="ControllerModel.Properties"/>.
|
||||
/// </summary>
|
||||
public IDictionary<object, object> Properties { get; }
|
||||
|
||||
public override string Format()
|
||||
{
|
||||
return LogFormatter.FormatStructure(this);
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
|||
action.Filters.Add(new AuthorizeAttribute());
|
||||
action.HttpMethods.Add("GET");
|
||||
action.RouteConstraints.Add(new AreaAttribute("Admin"));
|
||||
action.Properties.Add(new KeyValuePair<object, object>("test key", "test value"));
|
||||
|
||||
// Act
|
||||
var action2 = new ActionModel(action);
|
||||
|
|
@ -60,6 +61,7 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
|||
// Assert
|
||||
foreach (var property in typeof(ActionModel).GetProperties())
|
||||
{
|
||||
// Reflection is used to make sure the test fails when a new property is added.
|
||||
if (property.Name.Equals("ApiExplorer") ||
|
||||
property.Name.Equals("AttributeRouteModel") ||
|
||||
property.Name.Equals("Parameters"))
|
||||
|
|
@ -78,6 +80,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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
|||
controller.ControllerName = "cool";
|
||||
controller.Filters.Add(new AuthorizeAttribute());
|
||||
controller.RouteConstraints.Add(new AreaAttribute("Admin"));
|
||||
controller.Properties.Add(new KeyValuePair<object, object>("test key", "test value"));
|
||||
|
||||
// Act
|
||||
var controller2 = new ControllerModel(controller);
|
||||
|
|
@ -81,6 +82,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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNet.Mvc.ApplicationModels;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class ControllerActionDescriptorBuilderTest
|
||||
{
|
||||
[Fact]
|
||||
public void Build_WithPropertiesSet_FromApplicationModel()
|
||||
{
|
||||
// Arrange
|
||||
var applicationModel = new ApplicationModel();
|
||||
applicationModel.Properties["test"] = "application";
|
||||
|
||||
var controller = new ControllerModel(typeof(TestController).GetTypeInfo(),
|
||||
new List<object>() { });
|
||||
controller.Application = applicationModel;
|
||||
applicationModel.Controllers.Add(controller);
|
||||
|
||||
var methodInfo = typeof(TestController).GetMethod("SomeAction");
|
||||
var actionModel = new ActionModel(methodInfo, new List<object>() { });
|
||||
actionModel.Controller = controller;
|
||||
controller.Actions.Add(actionModel);
|
||||
|
||||
// Act
|
||||
var descriptors = ControllerActionDescriptorBuilder.Build(applicationModel);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("application", descriptors.Single().Properties["test"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_WithPropertiesSet_ControllerOverwritesApplicationModel()
|
||||
{
|
||||
// Arrange
|
||||
var applicationModel = new ApplicationModel();
|
||||
applicationModel.Properties["test"] = "application";
|
||||
|
||||
var controller = new ControllerModel(typeof(TestController).GetTypeInfo(),
|
||||
new List<object>() { });
|
||||
controller.Application = applicationModel;
|
||||
controller.Properties["test"] = "controller";
|
||||
applicationModel.Controllers.Add(controller);
|
||||
|
||||
var methodInfo = typeof(TestController).GetMethod("SomeAction");
|
||||
var actionModel = new ActionModel(methodInfo, new List<object>() { });
|
||||
actionModel.Controller = controller;
|
||||
controller.Actions.Add(actionModel);
|
||||
|
||||
// Act
|
||||
var descriptors = ControllerActionDescriptorBuilder.Build(applicationModel);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("controller", descriptors.Single().Properties["test"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_WithPropertiesSet_ActionOverwritesApplicationAndControllerModel()
|
||||
{
|
||||
// Arrange
|
||||
var applicationModel = new ApplicationModel();
|
||||
applicationModel.Properties["test"] = "application";
|
||||
|
||||
var controller = new ControllerModel(typeof(TestController).GetTypeInfo(),
|
||||
new List<object>() { });
|
||||
controller.Application = applicationModel;
|
||||
controller.Properties["test"] = "controller";
|
||||
applicationModel.Controllers.Add(controller);
|
||||
|
||||
var methodInfo = typeof(TestController).GetMethod("SomeAction");
|
||||
var actionModel = new ActionModel(methodInfo, new List<object>() { });
|
||||
actionModel.Controller = controller;
|
||||
actionModel.Properties["test"] = "action";
|
||||
controller.Actions.Add(actionModel);
|
||||
|
||||
// Act
|
||||
var descriptors = ControllerActionDescriptorBuilder.Build(applicationModel);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("action", descriptors.Single().Properties["test"]);
|
||||
}
|
||||
|
||||
private class TestController
|
||||
{
|
||||
public void SomeAction() { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -64,7 +64,57 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
|||
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal("CoolMetadata", body);
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ApplicationModel_AddPropertyToActionDescriptor_FromApplicationModel()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_services, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/Home/GetCommonDescription");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal("Common Application Description", body);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ApplicationModel_AddPropertyToActionDescriptor_ControllerModelOverwritesCommonApplicationProperty()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_services, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/ApplicationModel/GetControllerDescription");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal("Common Controller Description", body);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ApplicationModel_ProvidesMetadataToActionDescriptor_ActionModelOverwritesControllerModelProperty()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_services, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/ApplicationModel/GetActionSpecificDescription");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal("Specific Action Description", body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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;
|
||||
|
||||
namespace ApplicationModelWebSite
|
||||
{
|
||||
// This controller uses an reflected model attribute to add arbitrary data to controller and action model.
|
||||
[ControllerDescription("Common Controller Description")]
|
||||
public class ApplicationModelController : Controller
|
||||
{
|
||||
public string GetControllerDescription()
|
||||
{
|
||||
var actionDescriptor = (ControllerActionDescriptor)ActionContext.ActionDescriptor;
|
||||
return actionDescriptor.Properties["description"].ToString();
|
||||
}
|
||||
|
||||
[ActionDescription("Specific Action Description")]
|
||||
public string GetActionSpecificDescription()
|
||||
{
|
||||
var actionDescriptor = (ControllerActionDescriptor)ActionContext.ActionDescriptor;
|
||||
return actionDescriptor.Properties["description"].ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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;
|
||||
|
||||
namespace ApplicationModelWebSite
|
||||
{
|
||||
public class HomeController : Controller
|
||||
{
|
||||
public string GetCommonDescription()
|
||||
{
|
||||
var actionDescriptor = (ControllerActionDescriptor)ActionContext.ActionDescriptor;
|
||||
return actionDescriptor.Properties["description"].ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNet.Mvc.ApplicationModels;
|
||||
|
||||
|
||||
namespace ApplicationModelWebSite
|
||||
{
|
||||
public class ActionDescriptionAttribute : Attribute, IActionModelConvention
|
||||
{
|
||||
private object _value;
|
||||
|
||||
public ActionDescriptionAttribute(object value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
public void Apply(ActionModel model)
|
||||
{
|
||||
model.Properties["description"] = _value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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.ApplicationModels;
|
||||
|
||||
|
||||
namespace ApplicationModelWebSite
|
||||
{
|
||||
public class ApplicationDescription : IApplicationModelConvention
|
||||
{
|
||||
private string _description;
|
||||
|
||||
public ApplicationDescription(string description)
|
||||
{
|
||||
_description = description;
|
||||
}
|
||||
|
||||
public void Apply(ApplicationModel application)
|
||||
{
|
||||
application.Properties["description"] = _description;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNet.Mvc.ApplicationModels;
|
||||
|
||||
|
||||
namespace ApplicationModelWebSite
|
||||
{
|
||||
public class ControllerDescriptionAttribute : Attribute, IControllerModelConvention
|
||||
{
|
||||
private object _value;
|
||||
|
||||
public ControllerDescriptionAttribute(object value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
public void Apply(ControllerModel model)
|
||||
{
|
||||
model.Properties["description"] = _value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
|
||||
namespace ApplicationModelWebSite
|
||||
|
|
@ -15,6 +16,11 @@ namespace ApplicationModelWebSite
|
|||
app.UseServices(services =>
|
||||
{
|
||||
services.AddMvc(configuration);
|
||||
|
||||
services.Configure<MvcOptions>(options =>
|
||||
{
|
||||
options.ApplicationModelConventions.Add(new ApplicationDescription("Common Application Description"));
|
||||
});
|
||||
});
|
||||
|
||||
app.UseMvc(routes =>
|
||||
|
|
|
|||
Loading…
Reference in New Issue