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)
|
||||
{
|
||||
_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;
|
||||
|
|
|
|||
|
|
@ -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"]);
|
||||
}
|
||||
|
||||
[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)
|
||||
{
|
||||
RequestDelegate next = (c) => Task.FromResult<object>(null);
|
||||
|
|
|
|||
Loading…
Reference in New Issue