cr feedback

This commit is contained in:
Ryan Nowak 2014-07-17 14:11:06 -07:00
parent 745239f09f
commit 1b07c89322
8 changed files with 47 additions and 52 deletions

View File

@ -1,12 +1,18 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace Microsoft.AspNet.Mvc namespace Microsoft.AspNet.Mvc
{ {
public class ActionDescriptor public class ActionDescriptor
{ {
public ActionDescriptor()
{
RouteValueDefaults = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
}
public virtual string Name { get; set; } public virtual string Name { get; set; }
public List<RouteDataActionConstraint> RouteConstraints { get; set; } public List<RouteDataActionConstraint> RouteConstraints { get; set; }
@ -14,12 +20,12 @@ namespace Microsoft.AspNet.Mvc
/// <summary> /// <summary>
/// The set of route values that are added when this action is selected. /// The set of route values that are added when this action is selected.
/// </summary> /// </summary>
public Dictionary<string, object> RouteValues { get; set; } public Dictionary<string, object> RouteValueDefaults { get; private set; }
/// <summary> /// <summary>
/// The route template. May be null if the action has no attribute routes. /// The attribute route template. May be null if the action has no attribute routes.
/// </summary> /// </summary>
public string RouteTemplate { get; set; } public string AttributeRouteTemplate { get; set; }
public List<HttpMethodConstraint> MethodConstraints { get; set; } public List<HttpMethodConstraint> MethodConstraints { get; set; }

View File

@ -217,7 +217,7 @@
<Compile Include="KnownRouteValueConstraint.cs" /> <Compile Include="KnownRouteValueConstraint.cs" />
<Compile Include="RouteKeyHandling.cs" /> <Compile Include="RouteKeyHandling.cs" />
<Compile Include="Routing\AttributeRoute.cs" /> <Compile Include="Routing\AttributeRoute.cs" />
<Compile Include="Routing\AttributeRouteGenerationEntry.cs" /> <Compile Include="Routing\AttributeRouteLinkGenerationEntry.cs" />
<Compile Include="Routing\AttributeRouteMatchingEntry.cs" /> <Compile Include="Routing\AttributeRouteMatchingEntry.cs" />
<Compile Include="Routing\AttributeRoutePrecedence.cs" /> <Compile Include="Routing\AttributeRoutePrecedence.cs" />
<Compile Include="Routing\AttributeRouteTemplate.cs" /> <Compile Include="Routing\AttributeRouteTemplate.cs" />

View File

@ -38,9 +38,9 @@ namespace Microsoft.AspNet.Mvc
return; return;
} }
if (actionDescriptor.RouteValues != null) if (actionDescriptor.RouteValueDefaults != null)
{ {
foreach (var kvp in actionDescriptor.RouteValues) foreach (var kvp in actionDescriptor.RouteValueDefaults)
{ {
if (!context.RouteData.Values.ContainsKey(kvp.Key)) if (!context.RouteData.Values.ContainsKey(kvp.Key))
{ {

View File

@ -213,19 +213,17 @@ namespace Microsoft.AspNet.Mvc
{ {
// An attribute routed action will ignore conventional routed constraints. We still // An attribute routed action will ignore conventional routed constraints. We still
// want to provide these values as ambient values. // want to provide these values as ambient values.
var ambientValues = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
foreach (var constraint in actionDescriptor.RouteConstraints) foreach (var constraint in actionDescriptor.RouteConstraints)
{ {
ambientValues.Add(constraint.RouteKey, constraint.RouteValue); actionDescriptor.RouteValueDefaults.Add(constraint.RouteKey, constraint.RouteValue);
} }
actionDescriptor.RouteValues = ambientValues; // TODO #738 - this currently has parity with what we did in MVC5 when a template uses
// parameters like 'area', 'controller', and 'action. This needs to be changed as
// TODO #738 - this currently has parity with what we did in MVC5 when a template uses parameters // part of #738.
// like 'area', 'controller', and 'action. This needs to be reconsidered as part of #738.
// //
// For instance, consider actions mapped with api/Blog/{action}. The value of {action} needs to // For instance, consider actions mapped with api/Blog/{action}. The value of {action}
// passed to action selection to choose the right action. // needs to passed to action selection to choose the right action.
var template = TemplateParser.Parse(templateText, _constraintResolver); var template = TemplateParser.Parse(templateText, _constraintResolver);
var routeConstraints = new List<RouteDataActionConstraint>(); var routeConstraints = new List<RouteDataActionConstraint>();
@ -246,7 +244,7 @@ namespace Microsoft.AspNet.Mvc
actionDescriptor.RouteConstraints = routeConstraints; actionDescriptor.RouteConstraints = routeConstraints;
actionDescriptor.RouteTemplate = templateText; actionDescriptor.AttributeRouteTemplate = templateText;
} }
} }
@ -265,7 +263,7 @@ namespace Microsoft.AspNet.Mvc
{ {
foreach (var key in removalConstraints) foreach (var key in removalConstraints)
{ {
if (actionDescriptor.RouteTemplate == null) if (actionDescriptor.AttributeRouteTemplate == null)
{ {
if (!HasConstraint(actionDescriptor.RouteConstraints, key)) if (!HasConstraint(actionDescriptor.RouteConstraints, key))
{ {
@ -274,13 +272,6 @@ namespace Microsoft.AspNet.Mvc
RouteKeyHandling.DenyKey)); RouteKeyHandling.DenyKey));
} }
} }
else
{
if (!actionDescriptor.RouteValues.ContainsKey(key))
{
actionDescriptor.RouteValues.Add(key, null);
}
}
} }
} }

View File

@ -17,7 +17,7 @@ namespace Microsoft.AspNet.Mvc.Routing
{ {
private readonly IRouter _next; private readonly IRouter _next;
private readonly TemplateRoute[] _matchingRoutes; private readonly TemplateRoute[] _matchingRoutes;
private readonly AttributeRouteGenerationEntry[] _generationEntries; private readonly AttributeRouteLinkGenerationEntry[] _linkGenerationEntries;
/// <summary> /// <summary>
/// Creates a new <see cref="AttributeRoute"/>. /// Creates a new <see cref="AttributeRoute"/>.
@ -27,7 +27,7 @@ namespace Microsoft.AspNet.Mvc.Routing
public AttributeRoute( public AttributeRoute(
[NotNull] IRouter next, [NotNull] IRouter next,
[NotNull] IEnumerable<AttributeRouteMatchingEntry> matchingEntries, [NotNull] IEnumerable<AttributeRouteMatchingEntry> matchingEntries,
[NotNull] IEnumerable<AttributeRouteGenerationEntry> generationEntries) [NotNull] IEnumerable<AttributeRouteLinkGenerationEntry> linkGenerationEntries)
{ {
_next = next; _next = next;
@ -35,9 +35,9 @@ namespace Microsoft.AspNet.Mvc.Routing
// a good data-structure here. See #740 // a good data-structure here. See #740
_matchingRoutes = matchingEntries.OrderBy(e => e.Precedence).Select(e => e.Route).ToArray(); _matchingRoutes = matchingEntries.OrderBy(e => e.Precedence).Select(e => e.Route).ToArray();
// FOR RIGHT NOW - this is just an array of binders. We'll follow up by implementing // FOR RIGHT NOW - this is just an array of entries. We'll follow up by implementing
// a good data-structure here. See #741 // a good data-structure here. See #741
_generationEntries = generationEntries.OrderBy(e => e.Precedence).ToArray(); _linkGenerationEntries = linkGenerationEntries.OrderBy(e => e.Precedence).ToArray();
} }
/// <inheritdoc /> /// <inheritdoc />
@ -61,7 +61,7 @@ namespace Microsoft.AspNet.Mvc.Routing
// and controller. // and controller.
// //
// Building a proper data structure to optimize this is tracked by #741 // Building a proper data structure to optimize this is tracked by #741
foreach (var entry in _generationEntries) foreach (var entry in _linkGenerationEntries)
{ {
var isMatch = true; var isMatch = true;
foreach (var requiredLinkValue in entry.RequiredLinkValues) foreach (var requiredLinkValue in entry.RequiredLinkValues)
@ -73,23 +73,21 @@ namespace Microsoft.AspNet.Mvc.Routing
} }
} }
if (!isMatch) if (isMatch)
{ {
continue; var path = GenerateLink(context, entry);
} if (path != null)
{
var path = GenerateLink(context, entry); context.IsBound = true;
if (path != null) return path;
{ }
context.IsBound = true;
return path;
} }
} }
return null; return null;
} }
private string GenerateLink(VirtualPathContext context, AttributeRouteGenerationEntry entry) private string GenerateLink(VirtualPathContext context, AttributeRouteLinkGenerationEntry entry)
{ {
// In attribute the context includes the values that are used to select this entry - typically // In attribute the context includes the values that are used to select this entry - typically
// these will be the standard 'action', 'controller' and maybe 'area' tokens. However, we don't // these will be the standard 'action', 'controller' and maybe 'area' tokens. However, we don't
@ -135,7 +133,7 @@ namespace Microsoft.AspNet.Mvc.Routing
RouteDirection.UrlGeneration); RouteDirection.UrlGeneration);
if (!matched) if (!matched)
{ {
// A constrant rejected this link. // A constraint rejected this link.
return null; return null;
} }

View File

@ -11,7 +11,7 @@ namespace Microsoft.AspNet.Mvc.Routing
/// Used to build an <see cref="AttributeRoute"/>. Represents an individual URL-generating route that will be /// Used to build an <see cref="AttributeRoute"/>. Represents an individual URL-generating route that will be
/// aggregated into the <see cref="AttributeRoute"/>. /// aggregated into the <see cref="AttributeRoute"/>.
/// </summary> /// </summary>
public class AttributeRouteGenerationEntry public class AttributeRouteLinkGenerationEntry
{ {
/// <summary> /// <summary>
/// The <see cref="TemplateBinder"/>. /// The <see cref="TemplateBinder"/>.

View File

@ -31,7 +31,7 @@ namespace Microsoft.AspNet.Mvc.Routing
// We're creating one AttributeRouteGenerationEntry per action. This allows us to match the intended // We're creating one AttributeRouteGenerationEntry per action. This allows us to match the intended
// action by expected route values, and then use the TemplateBinder to generate the link. // action by expected route values, and then use the TemplateBinder to generate the link.
var generationEntries = new List<AttributeRouteGenerationEntry>(); var generationEntries = new List<AttributeRouteLinkGenerationEntry>();
foreach (var routeInfo in routeInfos) foreach (var routeInfo in routeInfos)
{ {
var defaults = routeInfo.ParsedTemplate.Parameters var defaults = routeInfo.ParsedTemplate.Parameters
@ -42,13 +42,13 @@ namespace Microsoft.AspNet.Mvc.Routing
.Where(p => p.InlineConstraint != null) .Where(p => p.InlineConstraint != null)
.ToDictionary(p => p.Name, p => p.InlineConstraint, StringComparer.OrdinalIgnoreCase); .ToDictionary(p => p.Name, p => p.InlineConstraint, StringComparer.OrdinalIgnoreCase);
generationEntries.Add(new AttributeRouteGenerationEntry() generationEntries.Add(new AttributeRouteLinkGenerationEntry()
{ {
Binder = new TemplateBinder(routeInfo.ParsedTemplate, defaults), Binder = new TemplateBinder(routeInfo.ParsedTemplate, defaults),
Defaults = defaults, Defaults = defaults,
Constraints = constraints, Constraints = constraints,
Precedence = routeInfo.Precedence, Precedence = routeInfo.Precedence,
RequiredLinkValues = routeInfo.ActionDescriptor.RouteValues, RequiredLinkValues = routeInfo.ActionDescriptor.RouteValueDefaults,
RouteGroup = routeInfo.RouteGroup, RouteGroup = routeInfo.RouteGroup,
Template = routeInfo.ParsedTemplate, Template = routeInfo.ParsedTemplate,
}); });
@ -108,7 +108,7 @@ namespace Microsoft.AspNet.Mvc.Routing
{ {
var routeInfos = new List<RouteInfo>(); var routeInfos = new List<RouteInfo>();
foreach (var action in actions.Where(a => a.RouteTemplate != null)) foreach (var action in actions.Where(a => a.AttributeRouteTemplate != null))
{ {
var constraint = action.RouteConstraints var constraint = action.RouteConstraints
.Where(c => c.RouteKey == AttributeRouting.RouteGroupKey) .Where(c => c.RouteKey == AttributeRouting.RouteGroupKey)
@ -121,14 +121,14 @@ namespace Microsoft.AspNet.Mvc.Routing
continue; continue;
} }
var parsedTemplate = TemplateParser.Parse(action.RouteTemplate, constraintResolver); var parsedTemplate = TemplateParser.Parse(action.AttributeRouteTemplate, constraintResolver);
routeInfos.Add(new RouteInfo() routeInfos.Add(new RouteInfo()
{ {
ActionDescriptor = action, ActionDescriptor = action,
ParsedTemplate = parsedTemplate, ParsedTemplate = parsedTemplate,
Precedence = AttributeRoutePrecedence.Compute(parsedTemplate), Precedence = AttributeRoutePrecedence.Compute(parsedTemplate),
RouteGroup = constraint.RouteValue, RouteGroup = constraint.RouteValue,
RouteTemplate = action.RouteTemplate, RouteTemplate = action.AttributeRouteTemplate,
}); });
} }

View File

@ -306,11 +306,11 @@ namespace Microsoft.AspNet.Mvc.Routing
new RouteValueDictionary(values)); new RouteValueDictionary(values));
} }
private static AttributeRouteGenerationEntry CreateGenerationEntry(string template, object requiredValues) private static AttributeRouteLinkGenerationEntry CreateGenerationEntry(string template, object requiredValues)
{ {
var constraintResolver = CreateConstraintResolver(); var constraintResolver = CreateConstraintResolver();
var entry = new AttributeRouteGenerationEntry(); var entry = new AttributeRouteLinkGenerationEntry();
entry.Template = TemplateParser.Parse(template, constraintResolver); entry.Template = TemplateParser.Parse(template, constraintResolver);
var defaults = entry.Template.Parameters var defaults = entry.Template.Parameters
@ -342,22 +342,22 @@ namespace Microsoft.AspNet.Mvc.Routing
return new DefaultInlineConstraintResolver(services, optionsMock.Object); return new DefaultInlineConstraintResolver(services, optionsMock.Object);
} }
private static AttributeRoute CreateAttributeRoute(AttributeRouteGenerationEntry entry) private static AttributeRoute CreateAttributeRoute(AttributeRouteLinkGenerationEntry entry)
{ {
return CreateAttributeRoute(new StubRouter(), entry); return CreateAttributeRoute(new StubRouter(), entry);
} }
private static AttributeRoute CreateAttributeRoute(IRouter next, AttributeRouteGenerationEntry entry) private static AttributeRoute CreateAttributeRoute(IRouter next, AttributeRouteLinkGenerationEntry entry)
{ {
return CreateAttributeRoute(next, new[] { entry }); return CreateAttributeRoute(next, new[] { entry });
} }
private static AttributeRoute CreateAttributeRoute(params AttributeRouteGenerationEntry[] entries) private static AttributeRoute CreateAttributeRoute(params AttributeRouteLinkGenerationEntry[] entries)
{ {
return CreateAttributeRoute(new StubRouter(), entries); return CreateAttributeRoute(new StubRouter(), entries);
} }
private static AttributeRoute CreateAttributeRoute(IRouter next, params AttributeRouteGenerationEntry[] entries) private static AttributeRoute CreateAttributeRoute(IRouter next, params AttributeRouteLinkGenerationEntry[] entries)
{ {
return new AttributeRoute( return new AttributeRoute(
next, next,