Fix #710 - add support for data tokens
This commit is contained in:
parent
97f54c532b
commit
4fa0b068b8
|
|
@ -0,0 +1,31 @@
|
||||||
|
// 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 System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Routing
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Metadata that defines data tokens for an <see cref="Endpoint"/>. This metadata
|
||||||
|
/// type provides data tokens value for <see cref="RouteData.DataTokens"/> associated
|
||||||
|
/// with an endpoint.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class DataTokensMetadata : IDataTokensMetadata
|
||||||
|
{
|
||||||
|
public DataTokensMetadata(IReadOnlyDictionary<string, object> dataTokens)
|
||||||
|
{
|
||||||
|
if (dataTokens == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(dataTokens));
|
||||||
|
}
|
||||||
|
|
||||||
|
DataTokens = dataTokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the data tokens.
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyDictionary<string, object> DataTokens { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -54,7 +54,20 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
if (_routeData == null)
|
if (_routeData == null)
|
||||||
{
|
{
|
||||||
_routeData = new RouteData(_values);
|
_routeData = _values == null ? new RouteData() : new RouteData(_values);
|
||||||
|
|
||||||
|
// Note: DataTokens won't update if someone else overwrites the Endpoint
|
||||||
|
// after route values has been set. This seems find since endpoints are a new
|
||||||
|
// feature and DataTokens are for back-compat.
|
||||||
|
var dataTokensMetadata = Endpoint?.Metadata.GetMetadata<IDataTokensMetadata>();
|
||||||
|
if (dataTokensMetadata != null)
|
||||||
|
{
|
||||||
|
var dataTokens = _routeData.DataTokens;
|
||||||
|
foreach (var kvp in dataTokensMetadata.DataTokens)
|
||||||
|
{
|
||||||
|
_routeData.DataTokens.Add(kvp.Key, kvp.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return _routeData;
|
return _routeData;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
// 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 System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Routing
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Metadata that defines data tokens for an <see cref="Endpoint"/>. This metadata
|
||||||
|
/// type provides data tokens value for <see cref="RouteData.DataTokens"/> associated
|
||||||
|
/// with an endpoint.
|
||||||
|
/// </summary>
|
||||||
|
public interface IDataTokensMetadata
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Get the data tokens.
|
||||||
|
/// </summary>
|
||||||
|
IReadOnlyDictionary<string, object> DataTokens { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
// 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 System.Linq;
|
||||||
|
using Microsoft.AspNetCore.Routing.Matching;
|
||||||
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Routing
|
||||||
|
{
|
||||||
|
public class EndpointFeatureTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void RouteData_CanIntializeDataTokens_WithMetadata()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expected = new RouteValueDictionary(new { foo = 17, bar = "hello", });
|
||||||
|
|
||||||
|
var feature = new EndpointFeature()
|
||||||
|
{
|
||||||
|
Endpoint = new MatcherEndpoint(
|
||||||
|
MatcherEndpoint.EmptyInvoker,
|
||||||
|
RoutePatternFactory.Parse("/"),
|
||||||
|
0,
|
||||||
|
new EndpointMetadataCollection(new DataTokensMetadata(expected)),
|
||||||
|
"test"),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var routeData = ((IRoutingFeature)feature).RouteData;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotSame(expected, routeData.DataTokens);
|
||||||
|
Assert.Equal(expected.OrderBy(kvp => kvp.Key), routeData.DataTokens.OrderBy(kvp => kvp.Key));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void RouteData_DataTokensIsEmpty_WithoutMetadata()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var feature = new EndpointFeature()
|
||||||
|
{
|
||||||
|
Endpoint = new MatcherEndpoint(
|
||||||
|
MatcherEndpoint.EmptyInvoker,
|
||||||
|
RoutePatternFactory.Parse("/"),
|
||||||
|
0,
|
||||||
|
new EndpointMetadataCollection(),
|
||||||
|
"test"),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var routeData = ((IRoutingFeature)feature).RouteData;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Empty(routeData.DataTokens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -82,6 +82,30 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
Assert.Equal("testValue", endpointFeature.Values["testKey"]);
|
Assert.Equal("testValue", endpointFeature.Values["testKey"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Invoke_BackCompatGetDataTokens_ValueUsedFromEndpointMetadata()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var httpContext = new DefaultHttpContext();
|
||||||
|
httpContext.RequestServices = new TestServiceProvider();
|
||||||
|
|
||||||
|
var middleware = CreateMiddleware();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await middleware.Invoke(httpContext);
|
||||||
|
var routeData = httpContext.GetRouteData();
|
||||||
|
var routeValue = httpContext.GetRouteValue("controller");
|
||||||
|
var endpointFeature = httpContext.Features.Get<IEndpointFeature>();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(routeData);
|
||||||
|
Assert.Equal("Home", (string)routeValue);
|
||||||
|
|
||||||
|
// changing route data value is reflected in endpoint feature values
|
||||||
|
routeData.Values["testKey"] = "testValue";
|
||||||
|
Assert.Equal("testValue", endpointFeature.Values["testKey"]);
|
||||||
|
}
|
||||||
|
|
||||||
private EndpointRoutingMiddleware CreateMiddleware(Logger<EndpointRoutingMiddleware> logger = null)
|
private EndpointRoutingMiddleware CreateMiddleware(Logger<EndpointRoutingMiddleware> logger = null)
|
||||||
{
|
{
|
||||||
RequestDelegate next = (c) => Task.FromResult<object>(null);
|
RequestDelegate next = (c) => Task.FromResult<object>(null);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue