From 4bcf236450edaecd07ab2e8b83b3879bf70c13be Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Tue, 24 Nov 2015 15:51:06 -0800 Subject: [PATCH] MVC companion to aspnet/Routing#238 This is a companion change to make the RouteValueDictionary type more promient. Using the concrete type here allows to avoid allocations in a lot of common scenarios. --- .../CreatedAtActionResult.cs | 7 +++--- .../CreatedAtRouteResult.cs | 7 +++--- .../RedirectToActionResult.cs | 23 +++++++++++++++---- .../RedirectToRouteResult.cs | 17 ++++++++++---- .../Routing/UrlHelper.cs | 10 ++++---- .../Controller.cs | 10 ++++---- .../ControllerTest.cs | 6 ++--- .../ControllerUnitTestabilityTests.cs | 8 +++---- 8 files changed, 54 insertions(+), 34 deletions(-) diff --git a/src/Microsoft.AspNet.Mvc.Core/CreatedAtActionResult.cs b/src/Microsoft.AspNet.Mvc.Core/CreatedAtActionResult.cs index c7f1233869..d45d74f4a6 100644 --- a/src/Microsoft.AspNet.Mvc.Core/CreatedAtActionResult.cs +++ b/src/Microsoft.AspNet.Mvc.Core/CreatedAtActionResult.cs @@ -2,11 +2,10 @@ // 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 Microsoft.AspNet.Http; using Microsoft.AspNet.Mvc.Core; +using Microsoft.AspNet.Routing; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Internal; using Microsoft.Net.Http.Headers; namespace Microsoft.AspNet.Mvc @@ -33,7 +32,7 @@ namespace Microsoft.AspNet.Mvc { ActionName = actionName; ControllerName = controllerName; - RouteValues = PropertyHelper.ObjectToDictionary(routeValues); + RouteValues = routeValues == null ? null : new RouteValueDictionary(routeValues); StatusCode = StatusCodes.Status201Created; } @@ -55,7 +54,7 @@ namespace Microsoft.AspNet.Mvc /// /// Gets or sets the route data to use for generating the URL. /// - public IDictionary RouteValues { get; set; } + public RouteValueDictionary RouteValues { get; set; } /// public override void OnFormatting(ActionContext context) diff --git a/src/Microsoft.AspNet.Mvc.Core/CreatedAtRouteResult.cs b/src/Microsoft.AspNet.Mvc.Core/CreatedAtRouteResult.cs index 80143dc36e..3a63636d3a 100644 --- a/src/Microsoft.AspNet.Mvc.Core/CreatedAtRouteResult.cs +++ b/src/Microsoft.AspNet.Mvc.Core/CreatedAtRouteResult.cs @@ -2,11 +2,10 @@ // 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 Microsoft.AspNet.Http; using Microsoft.AspNet.Mvc.Core; +using Microsoft.AspNet.Routing; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Internal; using Microsoft.Net.Http.Headers; namespace Microsoft.AspNet.Mvc @@ -41,7 +40,7 @@ namespace Microsoft.AspNet.Mvc : base(value) { RouteName = routeName; - RouteValues = PropertyHelper.ObjectToDictionary(routeValues); + RouteValues = routeValues == null ? null : new RouteValueDictionary(routeValues); StatusCode = StatusCodes.Status201Created; } @@ -58,7 +57,7 @@ namespace Microsoft.AspNet.Mvc /// /// Gets or sets the route data to use for generating the URL. /// - public IDictionary RouteValues { get; set; } + public RouteValueDictionary RouteValues { get; set; } /// public override void OnFormatting(ActionContext context) diff --git a/src/Microsoft.AspNet.Mvc.Core/RedirectToActionResult.cs b/src/Microsoft.AspNet.Mvc.Core/RedirectToActionResult.cs index 627a6b3216..960b4bf1f6 100644 --- a/src/Microsoft.AspNet.Mvc.Core/RedirectToActionResult.cs +++ b/src/Microsoft.AspNet.Mvc.Core/RedirectToActionResult.cs @@ -2,10 +2,10 @@ // 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 Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Mvc.Logging; using Microsoft.AspNet.Mvc.ViewFeatures; +using Microsoft.AspNet.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -16,7 +16,7 @@ namespace Microsoft.AspNet.Mvc public RedirectToActionResult( string actionName, string controllerName, - IDictionary routeValues) + object routeValues) : this(actionName, controllerName, routeValues, permanent: false) { } @@ -24,25 +24,38 @@ namespace Microsoft.AspNet.Mvc public RedirectToActionResult( string actionName, string controllerName, - IDictionary routeValues, + object routeValues, bool permanent) { ActionName = actionName; ControllerName = controllerName; - RouteValues = routeValues; + RouteValues = routeValues == null ? null : new RouteValueDictionary(routeValues); Permanent = permanent; } + /// + /// Gets or sets the used to generate URLs. + /// public IUrlHelper UrlHelper { get; set; } + /// + /// Gets or sets the name of the action to use for generating the URL. + /// public string ActionName { get; set; } + /// + /// Gets or sets the name of the controller to use for generating the URL. + /// public string ControllerName { get; set; } - public IDictionary RouteValues { get; set; } + /// + /// Gets or sets the route data to use for generating the URL. + /// + public RouteValueDictionary RouteValues { get; set; } public bool Permanent { get; set; } + /// public override void ExecuteResult(ActionContext context) { if (context == null) diff --git a/src/Microsoft.AspNet.Mvc.Core/RedirectToRouteResult.cs b/src/Microsoft.AspNet.Mvc.Core/RedirectToRouteResult.cs index 555aff047d..2a3509cddc 100644 --- a/src/Microsoft.AspNet.Mvc.Core/RedirectToRouteResult.cs +++ b/src/Microsoft.AspNet.Mvc.Core/RedirectToRouteResult.cs @@ -2,12 +2,11 @@ // 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 Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Mvc.Logging; using Microsoft.AspNet.Mvc.ViewFeatures; +using Microsoft.AspNet.Routing; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Internal; using Microsoft.Extensions.Logging; namespace Microsoft.AspNet.Mvc @@ -32,18 +31,28 @@ namespace Microsoft.AspNet.Mvc bool permanent) { RouteName = routeName; - RouteValues = PropertyHelper.ObjectToDictionary(routeValues); + RouteValues = routeValues == null ? null : new RouteValueDictionary(routeValues); Permanent = permanent; } + /// + /// Gets or sets the used to generate URLs. + /// public IUrlHelper UrlHelper { get; set; } + /// + /// Gets or sets the name of the route to use for generating the URL. + /// public string RouteName { get; set; } - public IDictionary RouteValues { get; set; } + /// + /// Gets or sets the route data to use for generating the URL. + /// + public RouteValueDictionary RouteValues { get; set; } public bool Permanent { get; set; } + /// public override void ExecuteResult(ActionContext context) { if (context == null) diff --git a/src/Microsoft.AspNet.Mvc.Core/Routing/UrlHelper.cs b/src/Microsoft.AspNet.Mvc.Core/Routing/UrlHelper.cs index ec1d5d4443..2ee79f1897 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Routing/UrlHelper.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Routing/UrlHelper.cs @@ -30,7 +30,7 @@ namespace Microsoft.AspNet.Mvc.Routing _actionContextAccessor = actionContextAccessor; } - protected IDictionary AmbientValues => ActionContext.RouteData.Values; + protected RouteValueDictionary AmbientValues => ActionContext.RouteData.Values; protected ActionContext ActionContext => _actionContextAccessor.ActionContext; @@ -46,7 +46,7 @@ namespace Microsoft.AspNet.Mvc.Routing throw new ArgumentNullException(nameof(actionContext)); } - var valuesDictionary = PropertyHelper.ObjectToDictionary(actionContext.Values); + var valuesDictionary = new RouteValueDictionary(actionContext.Values); if (actionContext.Action == null) { @@ -106,7 +106,7 @@ namespace Microsoft.AspNet.Mvc.Routing throw new ArgumentNullException(nameof(routeContext)); } - var valuesDictionary = PropertyHelper.ObjectToDictionary(routeContext.Values); + var valuesDictionary = new RouteValueDictionary(routeContext.Values); var path = GeneratePathFromRoute(routeContext.RouteName, valuesDictionary); if (path == null) @@ -117,7 +117,7 @@ namespace Microsoft.AspNet.Mvc.Routing return GenerateUrl(routeContext.Protocol, routeContext.Host, path, routeContext.Fragment); } - private string GeneratePathFromRoute(IDictionary values) + private string GeneratePathFromRoute(RouteValueDictionary values) { return GeneratePathFromRoute(routeName: null, values: values); } @@ -129,7 +129,7 @@ namespace Microsoft.AspNet.Mvc.Routing /// The name of the route that is used to generate the URL. /// A dictionary that contains the parameters for a route. /// The absolute path of the URL. - protected virtual string GeneratePathFromRoute(string routeName, IDictionary values) + protected virtual string GeneratePathFromRoute(string routeName, RouteValueDictionary values) { var context = new VirtualPathContext(HttpContext, AmbientValues, values, routeName); var pathData = Router.GetVirtualPath(context); diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/Controller.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/Controller.cs index 677e1a7dd6..79f00a413f 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/Controller.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/Controller.cs @@ -706,7 +706,7 @@ namespace Microsoft.AspNet.Mvc string controllerName, object routeValues) { - return new RedirectToActionResult(actionName, controllerName, PropertyHelper.ObjectToDictionary(routeValues)) + return new RedirectToActionResult(actionName, controllerName, routeValues) { UrlHelper = Url, }; @@ -768,7 +768,7 @@ namespace Microsoft.AspNet.Mvc return new RedirectToActionResult( actionName, controllerName, - PropertyHelper.ObjectToDictionary(routeValues), + routeValues, permanent: true) { UrlHelper = Url, @@ -1101,7 +1101,7 @@ namespace Microsoft.AspNet.Mvc /// /// The name of the action to use for generating the URL. /// The content value to format in the entity body. - /// The created for the response. + /// The created for the response. [NonAction] public virtual CreatedAtActionResult CreatedAtAction(string actionName, object value) { @@ -1114,7 +1114,7 @@ namespace Microsoft.AspNet.Mvc /// The name of the action to use for generating the URL. /// The route data to use for generating the URL. /// The content value to format in the entity body. - /// The created for the response. + /// The created for the response. [NonAction] public virtual CreatedAtActionResult CreatedAtAction(string actionName, object routeValues, object value) { @@ -1128,7 +1128,7 @@ namespace Microsoft.AspNet.Mvc /// The name of the controller to use for generating the URL. /// The route data to use for generating the URL. /// The content value to format in the entity body. - /// The created for the response. + /// The created for the response. [NonAction] public virtual CreatedAtActionResult CreatedAtAction( string actionName, diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ControllerTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ControllerTest.cs index 63f782a0bf..2a7d2d36fe 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ControllerTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ControllerTest.cs @@ -1192,13 +1192,13 @@ namespace Microsoft.AspNet.Mvc.Test yield return new object[] { null, - Enumerable.Empty>() + null, }; yield return new object[] { new Dictionary { { "hello", "world" } }, - new[] { new KeyValuePair("hello", "world") } + new RouteValueDictionary() { { "hello", "world" } }, }; var expected2 = new Dictionary @@ -1210,7 +1210,7 @@ namespace Microsoft.AspNet.Mvc.Test yield return new object[] { new RouteValueDictionary(expected2), - expected2 + new RouteValueDictionary(expected2), }; } } diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ControllerUnitTestabilityTests.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ControllerUnitTestabilityTests.cs index a08585a5a2..d2ea0b1605 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ControllerUnitTestabilityTests.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ControllerUnitTestabilityTests.cs @@ -345,7 +345,7 @@ namespace Microsoft.AspNet.Mvc createdAtRouteResult = Assert.IsType(result); Assert.Null(createdAtRouteResult.RouteName); - Assert.Empty(createdAtRouteResult.RouteValues); + Assert.Null(createdAtRouteResult.RouteValues); Assert.Null(createdAtRouteResult.Value); } @@ -385,7 +385,7 @@ namespace Microsoft.AspNet.Mvc Assert.Null(createdAtActionResult.ActionName); Assert.Null(createdAtActionResult.ControllerName); Assert.Null(createdAtActionResult.Value); - Assert.Empty(createdAtActionResult.RouteValues); + Assert.Null(createdAtActionResult.RouteValues); } [Fact] @@ -418,7 +418,7 @@ namespace Microsoft.AspNet.Mvc redirectToRouteResult = Assert.IsType(result); Assert.Null(redirectToRouteResult.RouteName); - Assert.Empty(redirectToRouteResult.RouteValues); + Assert.Null(redirectToRouteResult.RouteValues); } [Fact] @@ -454,7 +454,7 @@ namespace Microsoft.AspNet.Mvc redirectToActionResult = Assert.IsType(result); Assert.Null(redirectToActionResult.ControllerName); Assert.Null(redirectToActionResult.ActionName); - Assert.Empty(redirectToActionResult.RouteValues); + Assert.Null(redirectToActionResult.RouteValues); } [Fact]