Add RoutesValues to HttpRequest (#1042)

This commit is contained in:
James Newton-King 2018-10-02 16:03:58 +13:00 committed by GitHub
parent e8d5a85c99
commit 5f75c07bbf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 105 additions and 0 deletions

View File

@ -4,6 +4,7 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Routing;
namespace Microsoft.AspNetCore.Http
{
@ -117,5 +118,11 @@ namespace Microsoft.AspNetCore.Http
/// </summary>
/// <returns></returns>
public abstract Task<IFormCollection> ReadFormAsync(CancellationToken cancellationToken = new CancellationToken());
/// <summary>
/// Gets the collection of route values for this request.
/// </summary>
/// <returns>The collection of route values for this request.</returns>
public virtual RouteValueDictionary RouteValues { get; set; }
}
}

View File

@ -0,0 +1,34 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Routing;
namespace Microsoft.AspNetCore.Http.Features
{
/// <summary>
/// A feature for routing values. Use <see cref="HttpContext.Features"/>
/// to access the values associated with the current request.
/// </summary>
public class RouteValuesFeature : IRouteValuesFeature
{
private RouteValueDictionary _routeValues;
/// <summary>
/// Gets or sets the <see cref="RouteValueDictionary"/> associated with the currrent
/// request.
/// </summary>
public RouteValueDictionary RouteValues
{
get
{
if (_routeValues == null)
{
_routeValues = new RouteValueDictionary();
}
return _routeValues;
}
set => _routeValues = value;
}
}
}

View File

@ -6,6 +6,7 @@ using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing;
using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Http.Internal
@ -17,6 +18,7 @@ namespace Microsoft.AspNetCore.Http.Internal
private readonly static Func<IFeatureCollection, IQueryFeature> _newQueryFeature = f => new QueryFeature(f);
private readonly static Func<HttpRequest, IFormFeature> _newFormFeature = r => new FormFeature(r);
private readonly static Func<IFeatureCollection, IRequestCookiesFeature> _newRequestCookiesFeature = f => new RequestCookiesFeature(f);
private readonly static Func<IFeatureCollection, IRouteValuesFeature> _newRouteValuesFeature = f => new RouteValuesFeature();
private HttpContext _context;
private FeatureReferences<FeatureInterfaces> _features;
@ -52,6 +54,9 @@ namespace Microsoft.AspNetCore.Http.Internal
private IRequestCookiesFeature RequestCookiesFeature =>
_features.Fetch(ref _features.Cache.Cookies, _newRequestCookiesFeature);
private IRouteValuesFeature RouteValuesFeature =>
_features.Fetch(ref _features.Cache.RouteValues, _newRouteValuesFeature);
public override PathString PathBase
{
get { return new PathString(HttpRequestFeature.PathBase); }
@ -151,12 +156,19 @@ namespace Microsoft.AspNetCore.Http.Internal
return FormFeature.ReadFormAsync(cancellationToken);
}
public override RouteValueDictionary RouteValues
{
get { return RouteValuesFeature.RouteValues; }
set { RouteValuesFeature.RouteValues = value; }
}
struct FeatureInterfaces
{
public IHttpRequestFeature Request;
public IQueryFeature Query;
public IFormFeature Form;
public IRequestCookiesFeature Cookies;
public IRouteValuesFeature RouteValues;
}
}
}

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Primitives;
using Xunit;
@ -194,6 +195,57 @@ namespace Microsoft.AspNetCore.Http.Internal
Assert.Equal(new[] { "name2=value2" }, cookieHeaders);
}
[Fact]
public void RouteValues_GetAndSet()
{
var context = new DefaultHttpContext();
var request = context.Request;
var routeValuesFeature = context.Features.Get<IRouteValuesFeature>();
// No feature set for initial DefaultHttpRequest
Assert.Null(routeValuesFeature);
// Route values returns empty collection by default
Assert.Empty(request.RouteValues);
// Get and set value on request route values
request.RouteValues["new"] = "setvalue";
Assert.Equal("setvalue", request.RouteValues["new"]);
routeValuesFeature = context.Features.Get<IRouteValuesFeature>();
// Accessing DefaultHttpRequest.RouteValues creates feature
Assert.NotNull(routeValuesFeature);
request.RouteValues = new RouteValueDictionary(new { key = "value" });
// Can set DefaultHttpRequest.RouteValues
Assert.NotNull(request.RouteValues);
Assert.Equal("value", request.RouteValues["key"]);
// DefaultHttpRequest.RouteValues uses feature
Assert.Equal(routeValuesFeature.RouteValues, request.RouteValues);
// Setting route values to null sets empty collection on request
routeValuesFeature.RouteValues = null;
Assert.Empty(request.RouteValues);
var customRouteValuesFeature = new CustomRouteValuesFeature
{
RouteValues = new RouteValueDictionary(new { key = "customvalue" })
};
context.Features.Set<IRouteValuesFeature>(customRouteValuesFeature);
// Can override DefaultHttpRequest.RouteValues with custom feature
Assert.Equal(customRouteValuesFeature.RouteValues, request.RouteValues);
// Can clear feature
context.Features.Set<IRouteValuesFeature>(null);
Assert.Empty(request.RouteValues);
}
private class CustomRouteValuesFeature : IRouteValuesFeature
{
public RouteValueDictionary RouteValues { get; set; }
}
private static HttpRequest CreateRequest(IHeaderDictionary headers)
{
var context = new DefaultHttpContext();