Simplify parameter transformer usage

This commit is contained in:
Ryan Nowak 2018-11-20 11:21:46 -08:00
parent a04dd4877c
commit c9887e027a
10 changed files with 44 additions and 31 deletions

View File

@ -50,6 +50,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
ActionMethod = other.ActionMethod; ActionMethod = other.ActionMethod;
ActionName = other.ActionName; ActionName = other.ActionName;
RouteParameterTransformer = other.RouteParameterTransformer;
// Not making a deep copy of the controller, this action still belongs to the same controller. // Not making a deep copy of the controller, this action still belongs to the same controller.
Controller = other.Controller; Controller = other.Controller;
@ -93,6 +94,18 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
public IList<ParameterModel> Parameters { get; } public IList<ParameterModel> Parameters { get; }
/// <summary>
/// Gets or sets an <see cref="IOutboundParameterTransformer"/> that will be used to transform
/// built-in route parameters such as <c>action</c>, <c>controller</c>, and <c>area</c> as well as
/// additional parameters specified by <see cref="RouteValues"/> into static segments in the route template.
/// </summary>
/// <remarks>
/// <para>
/// This feature only applies when using endpoint routing.
/// </para>
/// </remarks>
public IOutboundParameterTransformer RouteParameterTransformer { get; set; }
/// <summary> /// <summary>
/// Gets a collection of route values that must be present in the /// Gets a collection of route values that must be present in the
/// <see cref="RouteData.Values"/> for the corresponding action to be selected. /// <see cref="RouteData.Values"/> for the corresponding action to be selected.

View File

@ -159,20 +159,17 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
routeValues.TryAdd(kvp.Key, kvp.Value); routeValues.TryAdd(kvp.Key, kvp.Value);
} }
action.Properties.TryGetValue(typeof(IOutboundParameterTransformer), out var obj);
var transformer = obj as IOutboundParameterTransformer;
selector.AttributeRouteModel.Template = AttributeRouteModel.ReplaceTokens( selector.AttributeRouteModel.Template = AttributeRouteModel.ReplaceTokens(
selector.AttributeRouteModel.Template, selector.AttributeRouteModel.Template,
routeValues, routeValues,
transformer); action.RouteParameterTransformer);
if (selector.AttributeRouteModel.Name != null) if (selector.AttributeRouteModel.Name != null)
{ {
selector.AttributeRouteModel.Name = AttributeRouteModel.ReplaceTokens( selector.AttributeRouteModel.Name = AttributeRouteModel.ReplaceTokens(
selector.AttributeRouteModel.Name, selector.AttributeRouteModel.Name,
routeValues, routeValues,
transformer); action.RouteParameterTransformer);
} }
} }
catch (InvalidOperationException ex) catch (InvalidOperationException ex)

View File

@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
{ {
if (ShouldApply(action)) if (ShouldApply(action))
{ {
action.Properties[typeof(IOutboundParameterTransformer)] = _parameterTransformer; action.RouteParameterTransformer = _parameterTransformer;
} }
} }

View File

@ -55,6 +55,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
RelativePath = other.RelativePath; RelativePath = other.RelativePath;
ViewEnginePath = other.ViewEnginePath; ViewEnginePath = other.ViewEnginePath;
AreaName = other.AreaName; AreaName = other.AreaName;
RouteParameterTransformer = other.RouteParameterTransformer;
Properties = new Dictionary<object, object>(other.Properties); Properties = new Dictionary<object, object>(other.Properties);
Selectors = new List<SelectorModel>(other.Selectors.Select(m => new SelectorModel(m))); Selectors = new List<SelectorModel>(other.Selectors.Select(m => new SelectorModel(m)));
@ -113,5 +114,17 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
/// </para> /// </para>
/// </remarks> /// </remarks>
public IDictionary<string, string> RouteValues { get; } public IDictionary<string, string> RouteValues { get; }
/// <summary>
/// Gets or sets an <see cref="IOutboundParameterTransformer"/> that will be used to transform
/// built-in route parameters such as <c>action</c>, <c>controller</c>, and <c>area</c> as well as
/// additional parameters specified by <see cref="RouteValues"/> into static segments in the route template.
/// </summary>
/// <remarks>
/// <para>
/// This feature only applies when using endpoint routing.
/// </para>
/// </remarks>
public IOutboundParameterTransformer RouteParameterTransformer { get; set; }
} }
} }

View File

@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
{ {
if (ShouldApply(model)) if (ShouldApply(model))
{ {
model.Properties[typeof(IOutboundParameterTransformer)] = _parameterTransformer; model.RouteParameterTransformer = _parameterTransformer;
} }
} }

View File

@ -113,11 +113,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
private static string TransformPageRoute(PageRouteModel model, SelectorModel selectorModel) private static string TransformPageRoute(PageRouteModel model, SelectorModel selectorModel)
{ {
model.Properties.TryGetValue(typeof(IOutboundParameterTransformer), out var transformer);
var pageRouteTransformer = transformer as IOutboundParameterTransformer;
// Transformer not set on page route // Transformer not set on page route
if (pageRouteTransformer == null) if (model.RouteParameterTransformer == null)
{ {
return selectorModel.AttributeRouteModel.Template; return selectorModel.AttributeRouteModel.Template;
} }
@ -134,7 +131,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
var segments = pageRouteMetadata.PageRoute.Split('/'); var segments = pageRouteMetadata.PageRoute.Split('/');
for (var i = 0; i < segments.Length; i++) for (var i = 0; i < segments.Length; i++)
{ {
segments[i] = pageRouteTransformer.TransformOutbound(segments[i]); segments[i] = model.RouteParameterTransformer.TransformOutbound(segments[i]);
} }
var transformedPageRoute = string.Join("/", segments); var transformedPageRoute = string.Join("/", segments);

View File

@ -7,6 +7,8 @@ using System.Reflection;
using Microsoft.AspNetCore.Mvc.ActionConstraints; using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Routing;
using Moq;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Mvc.ApplicationModels namespace Microsoft.AspNetCore.Mvc.ApplicationModels
@ -75,6 +77,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
(typeof(TestController).GetTypeInfo(), (typeof(TestController).GetTypeInfo(),
new List<object>()); new List<object>());
action.Filters.Add(new MyFilterAttribute()); action.Filters.Add(new MyFilterAttribute());
action.RouteParameterTransformer = Mock.Of<IOutboundParameterTransformer>();
action.RouteValues.Add("key", "value"); action.RouteValues.Add("key", "value");
action.Properties.Add(new KeyValuePair<object, object>("test key", "test value")); action.Properties.Add(new KeyValuePair<object, object>("test key", "test value"));

View File

@ -3,11 +3,10 @@
using System; using System;
using System.Reflection; using System.Reflection;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Mvc.Test.ApplicationModels namespace Microsoft.AspNetCore.Mvc.ApplicationModels
{ {
public class RouteTokenTransformerConventionTest public class RouteTokenTransformerConventionTest
{ {
@ -28,8 +27,7 @@ namespace Microsoft.AspNetCore.Mvc.Test.ApplicationModels
convention.Apply(model); convention.Apply(model);
// Assert // Assert
Assert.True(model.Properties.TryGetValue(typeof(IOutboundParameterTransformer), out var routeTokenTransformer)); Assert.Same(transformer, model.RouteParameterTransformer);
Assert.Equal(transformer, routeTokenTransformer);
} }
[Fact] [Fact]
@ -49,7 +47,7 @@ namespace Microsoft.AspNetCore.Mvc.Test.ApplicationModels
convention.Apply(model); convention.Apply(model);
// Assert // Assert
Assert.False(model.Properties.TryGetValue(typeof(IOutboundParameterTransformer), out _)); Assert.Null(model.RouteParameterTransformer);
} }
private MethodInfo GetMethodInfo() private MethodInfo GetMethodInfo()

View File

@ -24,8 +24,7 @@ namespace Microsoft.AspNetCore.Mvc.Test.ApplicationModels
convention.Apply(model); convention.Apply(model);
// Assert // Assert
Assert.True(model.Properties.TryGetValue(typeof(IOutboundParameterTransformer), out var routeTokenTransformer)); Assert.Same(transformer, model.RouteParameterTransformer);
Assert.Equal(transformer, routeTokenTransformer);
} }
[Fact] [Fact]
@ -41,7 +40,7 @@ namespace Microsoft.AspNetCore.Mvc.Test.ApplicationModels
convention.Apply(model); convention.Apply(model);
// Assert // Assert
Assert.False(model.Properties.TryGetValue(typeof(IOutboundParameterTransformer), out _)); Assert.Null(model.RouteParameterTransformer);
} }
private class TestParameterTransformer : IOutboundParameterTransformer private class TestParameterTransformer : IOutboundParameterTransformer

View File

@ -8,12 +8,12 @@ using Microsoft.AspNetCore.Routing;
namespace RoutingWebSite namespace RoutingWebSite
{ {
public class ControllerRouteTokenTransformerConvention : IApplicationModelConvention public class ControllerRouteTokenTransformerConvention : RouteTokenTransformerConvention
{ {
private readonly Type _controllerType; private readonly Type _controllerType;
private readonly IOutboundParameterTransformer _parameterTransformer;
public ControllerRouteTokenTransformerConvention(Type controllerType, IOutboundParameterTransformer parameterTransformer) public ControllerRouteTokenTransformerConvention(Type controllerType, IOutboundParameterTransformer parameterTransformer)
: base(parameterTransformer)
{ {
if (parameterTransformer == null) if (parameterTransformer == null)
{ {
@ -21,18 +21,11 @@ namespace RoutingWebSite
} }
_controllerType = controllerType; _controllerType = controllerType;
_parameterTransformer = parameterTransformer;
} }
public void Apply(ApplicationModel application) protected override bool ShouldApply(ActionModel action)
{ {
foreach (var controller in application.Controllers.Where(c => c.ControllerType == _controllerType)) return action.Controller.ControllerType == _controllerType;
{
foreach (var action in controller.Actions)
{
action.Properties[typeof(IOutboundParameterTransformer)] = _parameterTransformer;
}
}
} }
} }
} }