Updated to make routing always use UrlEncoder.Default and not depend on DI to get it.
[Fixes #513] RedirectToAction with Non-English Characters in Parameters and Authentication Causes Error
This commit is contained in:
parent
8f62b6e5ba
commit
4184b2406d
|
|
@ -7,15 +7,12 @@ using System.Text.Encodings.Web;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Routing;
|
|
||||||
using Microsoft.AspNetCore.Routing.Internal;
|
using Microsoft.AspNetCore.Routing.Internal;
|
||||||
using Microsoft.AspNetCore.Routing.Template;
|
using Microsoft.AspNetCore.Routing.Template;
|
||||||
using Microsoft.AspNetCore.Routing.Tree;
|
using Microsoft.AspNetCore.Routing.Tree;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
using Microsoft.Extensions.ObjectPool;
|
using Microsoft.Extensions.ObjectPool;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Performance
|
namespace Microsoft.AspNetCore.Routing.Performance
|
||||||
{
|
{
|
||||||
|
|
@ -33,8 +30,7 @@ namespace Microsoft.AspNetCore.Routing.Performance
|
||||||
|
|
||||||
var treeBuilder = new TreeRouteBuilder(
|
var treeBuilder = new TreeRouteBuilder(
|
||||||
NullLoggerFactory.Instance,
|
NullLoggerFactory.Instance,
|
||||||
UrlEncoder.Default,
|
new DefaultObjectPool<UriBuildingContext>(new UriBuilderContextPooledObjectPolicy()),
|
||||||
new DefaultObjectPool<UriBuildingContext>(new UriBuilderContextPooledObjectPolicy(UrlEncoder.Default)),
|
|
||||||
new DefaultInlineConstraintResolver(new OptionsManager<RouteOptions>(new OptionsFactory<RouteOptions>(Enumerable.Empty<IConfigureOptions<RouteOptions>>(), Enumerable.Empty<IPostConfigureOptions<RouteOptions>>()))));
|
new DefaultInlineConstraintResolver(new OptionsManager<RouteOptions>(new OptionsFactory<RouteOptions>(Enumerable.Empty<IConfigureOptions<RouteOptions>>(), Enumerable.Empty<IPostConfigureOptions<RouteOptions>>()))));
|
||||||
|
|
||||||
treeBuilder.MapInbound(handler, TemplateParser.Parse("api/Widgets"), "default", 0);
|
treeBuilder.MapInbound(handler, TemplateParser.Parse("api/Widgets"), "default", 0);
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,11 @@
|
||||||
// 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;
|
||||||
using System.Text.Encodings.Web;
|
|
||||||
using Microsoft.AspNetCore.Routing;
|
using Microsoft.AspNetCore.Routing;
|
||||||
using Microsoft.AspNetCore.Routing.Internal;
|
using Microsoft.AspNetCore.Routing.Internal;
|
||||||
using Microsoft.AspNetCore.Routing.Tree;
|
using Microsoft.AspNetCore.Routing.Tree;
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.ObjectPool;
|
using Microsoft.Extensions.ObjectPool;
|
||||||
|
|
||||||
namespace Microsoft.Extensions.DependencyInjection
|
namespace Microsoft.Extensions.DependencyInjection
|
||||||
|
|
@ -29,17 +29,21 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
}
|
}
|
||||||
|
|
||||||
services.TryAddTransient<IInlineConstraintResolver, DefaultInlineConstraintResolver>();
|
services.TryAddTransient<IInlineConstraintResolver, DefaultInlineConstraintResolver>();
|
||||||
services.TryAddSingleton(UrlEncoder.Default);
|
|
||||||
services.TryAddSingleton<ObjectPool<UriBuildingContext>>(s =>
|
services.TryAddSingleton<ObjectPool<UriBuildingContext>>(s =>
|
||||||
{
|
{
|
||||||
var provider = s.GetRequiredService<ObjectPoolProvider>();
|
var provider = s.GetRequiredService<ObjectPoolProvider>();
|
||||||
var encoder = s.GetRequiredService<UrlEncoder>();
|
return provider.Create<UriBuildingContext>(new UriBuilderContextPooledObjectPolicy());
|
||||||
return provider.Create<UriBuildingContext>(new UriBuilderContextPooledObjectPolicy(encoder));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// The TreeRouteBuilder is a builder for creating routes, it should stay transient because it's
|
// The TreeRouteBuilder is a builder for creating routes, it should stay transient because it's
|
||||||
// stateful.
|
// stateful.
|
||||||
services.TryAddTransient<TreeRouteBuilder>();
|
services.TryAdd(ServiceDescriptor.Transient<TreeRouteBuilder>(s =>
|
||||||
|
{
|
||||||
|
var loggerFactory = s.GetRequiredService<ILoggerFactory>();
|
||||||
|
var objectPool = s.GetRequiredService<ObjectPool<UriBuildingContext>>();
|
||||||
|
var constraintResolver = s.GetRequiredService<IInlineConstraintResolver>();
|
||||||
|
return new TreeRouteBuilder(loggerFactory, objectPool, constraintResolver);
|
||||||
|
}));
|
||||||
|
|
||||||
services.TryAddSingleton(typeof(RoutingMarkerService));
|
services.TryAddSingleton(typeof(RoutingMarkerService));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
using Microsoft.Extensions.ObjectPool;
|
using Microsoft.Extensions.ObjectPool;
|
||||||
|
|
||||||
|
|
@ -9,21 +8,9 @@ namespace Microsoft.AspNetCore.Routing.Internal
|
||||||
{
|
{
|
||||||
public class UriBuilderContextPooledObjectPolicy : IPooledObjectPolicy<UriBuildingContext>
|
public class UriBuilderContextPooledObjectPolicy : IPooledObjectPolicy<UriBuildingContext>
|
||||||
{
|
{
|
||||||
private readonly UrlEncoder _encoder;
|
|
||||||
|
|
||||||
public UriBuilderContextPooledObjectPolicy(UrlEncoder encoder)
|
|
||||||
{
|
|
||||||
if (encoder == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(encoder));
|
|
||||||
}
|
|
||||||
|
|
||||||
_encoder = encoder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UriBuildingContext Create()
|
public UriBuildingContext Create()
|
||||||
{
|
{
|
||||||
return new UriBuildingContext(_encoder);
|
return new UriBuildingContext(UrlEncoder.Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Return(UriBuildingContext obj)
|
public bool Return(UriBuildingContext obj)
|
||||||
|
|
|
||||||
|
|
@ -241,9 +241,8 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
if (_binder == null)
|
if (_binder == null)
|
||||||
{
|
{
|
||||||
var urlEncoder = context.RequestServices.GetRequiredService<UrlEncoder>();
|
|
||||||
var pool = context.RequestServices.GetRequiredService<ObjectPool<UriBuildingContext>>();
|
var pool = context.RequestServices.GetRequiredService<ObjectPool<UriBuildingContext>>();
|
||||||
_binder = new TemplateBinder(urlEncoder, pool, ParsedTemplate, Defaults);
|
_binder = new TemplateBinder(UrlEncoder.Default, pool, ParsedTemplate, Defaults);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,13 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
private readonly RouteValueDictionary _filters;
|
private readonly RouteValueDictionary _filters;
|
||||||
private readonly RouteTemplate _template;
|
private readonly RouteTemplate _template;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of <see cref="TemplateBinder"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="urlEncoder">The <see cref="UrlEncoder"/>.</param>
|
||||||
|
/// <param name="pool">The <see cref="ObjectPool{T}"/>.</param>
|
||||||
|
/// <param name="template">The <see cref="RouteTemplate"/> to bind values to.</param>
|
||||||
|
/// <param name="defaults">The default values for <paramref name="template"/>.</param>
|
||||||
public TemplateBinder(
|
public TemplateBinder(
|
||||||
UrlEncoder urlEncoder,
|
UrlEncoder urlEncoder,
|
||||||
ObjectPool<UriBuildingContext> pool,
|
ObjectPool<UriBuildingContext> pool,
|
||||||
|
|
@ -90,8 +97,8 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasNewParameterValue &&
|
if (!hasNewParameterValue &&
|
||||||
!hasCurrentParameterValue &&
|
!hasCurrentParameterValue &&
|
||||||
_defaults?.ContainsKey(parameter.Name) != true)
|
_defaults?.ContainsKey(parameter.Name) != true)
|
||||||
{
|
{
|
||||||
// This is an unsatisfied parameter value and there are no defaults. We might still
|
// This is an unsatisfied parameter value and there are no defaults. We might still
|
||||||
|
|
|
||||||
|
|
@ -25,28 +25,49 @@ namespace Microsoft.AspNetCore.Routing.Tree
|
||||||
private readonly IInlineConstraintResolver _constraintResolver;
|
private readonly IInlineConstraintResolver _constraintResolver;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of <see cref="TreeRouteBuilder"/>.
|
/// <para>
|
||||||
|
/// This constructor is obsolete and will be removed in a future version. The recommended
|
||||||
|
/// alternative is the overload that does not take a UrlEncoder.
|
||||||
|
/// </para>
|
||||||
|
/// <para>Initializes a new instance of <see cref="TreeRouteBuilder"/>.</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
||||||
/// <param name="urlEncoder">The <see cref="UrlEncoder"/>.</param>
|
/// <param name="urlEncoder">The <see cref="UrlEncoder"/>.</param>
|
||||||
/// <param name="objectPool">The <see cref="ObjectPool{UrlBuildingContext}"/>.</param>
|
/// <param name="objectPool">The <see cref="ObjectPool{UrlBuildingContext}"/>.</param>
|
||||||
/// <param name="constraintResolver">The <see cref="IInlineConstraintResolver"/>.</param>
|
/// <param name="constraintResolver">The <see cref="IInlineConstraintResolver"/>.</param>
|
||||||
|
[Obsolete("This constructor is obsolete and will be removed in a future version. The recommended " +
|
||||||
|
"alternative is the overload that does not take a UrlEncoder.")]
|
||||||
public TreeRouteBuilder(
|
public TreeRouteBuilder(
|
||||||
ILoggerFactory loggerFactory,
|
ILoggerFactory loggerFactory,
|
||||||
UrlEncoder urlEncoder,
|
UrlEncoder urlEncoder,
|
||||||
ObjectPool<UriBuildingContext> objectPool,
|
ObjectPool<UriBuildingContext> objectPool,
|
||||||
IInlineConstraintResolver constraintResolver)
|
IInlineConstraintResolver constraintResolver)
|
||||||
|
: this(loggerFactory, objectPool, constraintResolver)
|
||||||
|
{
|
||||||
|
if (urlEncoder == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(urlEncoder));
|
||||||
|
}
|
||||||
|
|
||||||
|
_urlEncoder = urlEncoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of <see cref="TreeRouteBuilder"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
||||||
|
/// <param name="objectPool">The <see cref="ObjectPool{UrlBuildingContext}"/>.</param>
|
||||||
|
/// <param name="constraintResolver">The <see cref="IInlineConstraintResolver"/>.</param>
|
||||||
|
public TreeRouteBuilder(
|
||||||
|
ILoggerFactory loggerFactory,
|
||||||
|
ObjectPool<UriBuildingContext> objectPool,
|
||||||
|
IInlineConstraintResolver constraintResolver)
|
||||||
{
|
{
|
||||||
if (loggerFactory == null)
|
if (loggerFactory == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(loggerFactory));
|
throw new ArgumentNullException(nameof(loggerFactory));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (urlEncoder == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(urlEncoder));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (objectPool == null)
|
if (objectPool == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(objectPool));
|
throw new ArgumentNullException(nameof(objectPool));
|
||||||
|
|
@ -57,7 +78,7 @@ namespace Microsoft.AspNetCore.Routing.Tree
|
||||||
throw new ArgumentNullException(nameof(constraintResolver));
|
throw new ArgumentNullException(nameof(constraintResolver));
|
||||||
}
|
}
|
||||||
|
|
||||||
_urlEncoder = urlEncoder;
|
_urlEncoder = UrlEncoder.Default;
|
||||||
_objectPool = objectPool;
|
_objectPool = objectPool;
|
||||||
_constraintResolver = constraintResolver;
|
_constraintResolver = constraintResolver;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
@ -14,6 +15,7 @@ using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
using Microsoft.Extensions.ObjectPool;
|
using Microsoft.Extensions.ObjectPool;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using Microsoft.Extensions.WebEncoders.Testing;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -647,6 +649,37 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
Assert.Empty(pathData.DataTokens);
|
Assert.Empty(pathData.DataTokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetVirtualPath_AlwaysUsesDefaultUrlEncoder()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var services = new ServiceCollection();
|
||||||
|
services.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance);
|
||||||
|
services.AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>();
|
||||||
|
services.AddRouting();
|
||||||
|
// This test encoder should not be used by Routing and should always use the default one.
|
||||||
|
services.AddSingleton<UrlEncoder>(new UrlTestEncoder());
|
||||||
|
var httpContext = new DefaultHttpContext
|
||||||
|
{
|
||||||
|
RequestServices = services.BuildServiceProvider(),
|
||||||
|
};
|
||||||
|
|
||||||
|
var context = new VirtualPathContext(
|
||||||
|
httpContext,
|
||||||
|
values: new RouteValueDictionary(new { name = "name with %special #characters Jörn" }),
|
||||||
|
ambientValues: new RouteValueDictionary(new { controller = "Home", action = "Index" }));
|
||||||
|
|
||||||
|
var route = CreateRoute("{controller}/{action}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var pathData = route.GetVirtualPath(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("/Home/Index?name=name%20with%20%25special%20%23characters%20J%C3%B6rn", pathData.VirtualPath);
|
||||||
|
Assert.Same(route, pathData.Router);
|
||||||
|
Assert.Empty(pathData.DataTokens);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetVirtualPath_ForListOfStrings()
|
public void GetVirtualPath_ForListOfStrings()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ using Microsoft.AspNetCore.Routing.Internal;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.ObjectPool;
|
using Microsoft.Extensions.ObjectPool;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Microsoft.Extensions.WebEncoders.Testing;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Template.Tests
|
namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
|
|
@ -31,7 +30,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
"Test/{val1}/{val2}",
|
"Test/{val1}/{val2}",
|
||||||
new RouteValueDictionary(new {val1 = "", val2 = ""}),
|
new RouteValueDictionary(new {val1 = "", val2 = ""}),
|
||||||
new RouteValueDictionary(new {val1 = "a"}),
|
new RouteValueDictionary(new {val1 = "a"}),
|
||||||
"/UrlEncode[[Test]]/UrlEncode[[a]]"
|
"/Test/a"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Test/{val1}/{val2}/{val3}",
|
"Test/{val1}/{val2}/{val3}",
|
||||||
|
|
@ -43,67 +42,67 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
"Test/{val1}/{val2}",
|
"Test/{val1}/{val2}",
|
||||||
new RouteValueDictionary(new {val1 = "", val2 = ""}),
|
new RouteValueDictionary(new {val1 = "", val2 = ""}),
|
||||||
new RouteValueDictionary(new {val1 = "a", val2 = "b"}),
|
new RouteValueDictionary(new {val1 = "a", val2 = "b"}),
|
||||||
"/UrlEncode[[Test]]/UrlEncode[[a]]/UrlEncode[[b]]"
|
"/Test/a/b"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Test/{val1}/{val2}/{val3}",
|
"Test/{val1}/{val2}/{val3}",
|
||||||
new RouteValueDictionary(new {val1 = "", val2 = "", val3 = ""}),
|
new RouteValueDictionary(new {val1 = "", val2 = "", val3 = ""}),
|
||||||
new RouteValueDictionary(new {val1 = "a", val2 = "b", val3 = "c"}),
|
new RouteValueDictionary(new {val1 = "a", val2 = "b", val3 = "c"}),
|
||||||
"/UrlEncode[[Test]]/UrlEncode[[a]]/UrlEncode[[b]]/UrlEncode[[c]]"
|
"/Test/a/b/c"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Test/{val1}/{val2}/{val3}",
|
"Test/{val1}/{val2}/{val3}",
|
||||||
new RouteValueDictionary(new {val1 = "", val2 = "", val3 = ""}),
|
new RouteValueDictionary(new {val1 = "", val2 = "", val3 = ""}),
|
||||||
new RouteValueDictionary(new {val1 = "a", val2 = "b"}),
|
new RouteValueDictionary(new {val1 = "a", val2 = "b"}),
|
||||||
"/UrlEncode[[Test]]/UrlEncode[[a]]/UrlEncode[[b]]"
|
"/Test/a/b"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Test/{val1}/{val2}/{val3}",
|
"Test/{val1}/{val2}/{val3}",
|
||||||
new RouteValueDictionary(new {val1 = "", val2 = "", val3 = ""}),
|
new RouteValueDictionary(new {val1 = "", val2 = "", val3 = ""}),
|
||||||
new RouteValueDictionary(new {val1 = "a"}),
|
new RouteValueDictionary(new {val1 = "a"}),
|
||||||
"/UrlEncode[[Test]]/UrlEncode[[a]]"
|
"/Test/a"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Test/{val1}",
|
"Test/{val1}",
|
||||||
new RouteValueDictionary(new {val1 = "42", val2 = "", val3 = ""}),
|
new RouteValueDictionary(new {val1 = "42", val2 = "", val3 = ""}),
|
||||||
new RouteValueDictionary(),
|
new RouteValueDictionary(),
|
||||||
"/UrlEncode[[Test]]"
|
"/Test"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Test/{val1}/{val2}/{val3}",
|
"Test/{val1}/{val2}/{val3}",
|
||||||
new RouteValueDictionary(new {val1 = "42", val2 = (string)null, val3 = (string)null}),
|
new RouteValueDictionary(new {val1 = "42", val2 = (string)null, val3 = (string)null}),
|
||||||
new RouteValueDictionary(),
|
new RouteValueDictionary(),
|
||||||
"/UrlEncode[[Test]]"
|
"/Test"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Test/{val1}/{val2}/{val3}/{val4}",
|
"Test/{val1}/{val2}/{val3}/{val4}",
|
||||||
new RouteValueDictionary(new {val1 = "21", val2 = "", val3 = "", val4 = ""}),
|
new RouteValueDictionary(new {val1 = "21", val2 = "", val3 = "", val4 = ""}),
|
||||||
new RouteValueDictionary(new {val1 = "42", val2 = "11", val3 = "", val4 = ""}),
|
new RouteValueDictionary(new {val1 = "42", val2 = "11", val3 = "", val4 = ""}),
|
||||||
"/UrlEncode[[Test]]/UrlEncode[[42]]/UrlEncode[[11]]"
|
"/Test/42/11"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Test/{val1}/{val2}/{val3}",
|
"Test/{val1}/{val2}/{val3}",
|
||||||
new RouteValueDictionary(new {val1 = "21", val2 = "", val3 = ""}),
|
new RouteValueDictionary(new {val1 = "21", val2 = "", val3 = ""}),
|
||||||
new RouteValueDictionary(new {val1 = "42"}),
|
new RouteValueDictionary(new {val1 = "42"}),
|
||||||
"/UrlEncode[[Test]]/UrlEncode[[42]]"
|
"/Test/42"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Test/{val1}/{val2}/{val3}/{val4}",
|
"Test/{val1}/{val2}/{val3}/{val4}",
|
||||||
new RouteValueDictionary(new {val1 = "21", val2 = "", val3 = "", val4 = ""}),
|
new RouteValueDictionary(new {val1 = "21", val2 = "", val3 = "", val4 = ""}),
|
||||||
new RouteValueDictionary(new {val1 = "42", val2 = "11"}),
|
new RouteValueDictionary(new {val1 = "42", val2 = "11"}),
|
||||||
"/UrlEncode[[Test]]/UrlEncode[[42]]/UrlEncode[[11]]"
|
"/Test/42/11"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Test/{val1}/{val2}/{val3}",
|
"Test/{val1}/{val2}/{val3}",
|
||||||
new RouteValueDictionary(new {val1 = "21", val2 = (string)null, val3 = (string)null}),
|
new RouteValueDictionary(new {val1 = "21", val2 = (string)null, val3 = (string)null}),
|
||||||
new RouteValueDictionary(new {val1 = "42"}),
|
new RouteValueDictionary(new {val1 = "42"}),
|
||||||
"/UrlEncode[[Test]]/UrlEncode[[42]]"
|
"/Test/42"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Test/{val1}/{val2}/{val3}/{val4}",
|
"Test/{val1}/{val2}/{val3}/{val4}",
|
||||||
new RouteValueDictionary(new {val1 = "21", val2 = (string)null, val3 = (string)null, val4 = (string)null}),
|
new RouteValueDictionary(new {val1 = "21", val2 = (string)null, val3 = (string)null, val4 = (string)null}),
|
||||||
new RouteValueDictionary(new {val1 = "42", val2 = "11"}),
|
new RouteValueDictionary(new {val1 = "42", val2 = "11"}),
|
||||||
"/UrlEncode[[Test]]/UrlEncode[[42]]/UrlEncode[[11]]"
|
"/Test/42/11"
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -116,10 +115,9 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
string expected)
|
string expected)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var encoder = new UrlTestEncoder();
|
|
||||||
var binder = new TemplateBinder(
|
var binder = new TemplateBinder(
|
||||||
encoder,
|
UrlEncoder.Default,
|
||||||
new DefaultObjectPoolProvider().Create(new UriBuilderContextPooledObjectPolicy(encoder)),
|
new DefaultObjectPoolProvider().Create(new UriBuilderContextPooledObjectPolicy()),
|
||||||
TemplateParser.Parse(template),
|
TemplateParser.Parse(template),
|
||||||
defaults);
|
defaults);
|
||||||
|
|
||||||
|
|
@ -157,7 +155,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
null,
|
null,
|
||||||
new RouteValueDictionary(new { lang = "en", region = "US" }),
|
new RouteValueDictionary(new { lang = "en", region = "US" }),
|
||||||
new RouteValueDictionary(new { lang = "xx", region = "yy" }),
|
new RouteValueDictionary(new { lang = "xx", region = "yy" }),
|
||||||
"/UrlEncode[[language]]/UrlEncode[[xx]]UrlEncode[[-]]UrlEncode[[yy]]");
|
"/language/xx-yy");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -168,7 +166,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
null,
|
null,
|
||||||
new RouteValueDictionary(new { lang = "en", region = "US" }),
|
new RouteValueDictionary(new { lang = "en", region = "US" }),
|
||||||
new RouteValueDictionary(new { lang = "xx", region = "yy" }),
|
new RouteValueDictionary(new { lang = "xx", region = "yy" }),
|
||||||
"/UrlEncode[[language]]/UrlEncode[[xx]]UrlEncode[[-]]UrlEncode[[yy]]UrlEncode[[a]]");
|
"/language/xx-yya");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -179,7 +177,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
null,
|
null,
|
||||||
new RouteValueDictionary(new { lang = "en", region = "US" }),
|
new RouteValueDictionary(new { lang = "en", region = "US" }),
|
||||||
new RouteValueDictionary(new { lang = "xx", region = "yy" }),
|
new RouteValueDictionary(new { lang = "xx", region = "yy" }),
|
||||||
"/UrlEncode[[language]]/UrlEncode[[a]]UrlEncode[[xx]]UrlEncode[[-]]UrlEncode[[yy]]");
|
"/language/axx-yy");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TheoryData OptionalParamValues =>
|
public static TheoryData OptionalParamValues =>
|
||||||
|
|
@ -193,66 +191,66 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
new RouteValueDictionary(new {val1 = "someval1", val2 = "someval2"}),
|
new RouteValueDictionary(new {val1 = "someval1", val2 = "someval2"}),
|
||||||
new RouteValueDictionary(new {val3 = "someval3"}),
|
new RouteValueDictionary(new {val3 = "someval3"}),
|
||||||
new RouteValueDictionary(new {val3 = "someval3"}),
|
new RouteValueDictionary(new {val3 = "someval3"}),
|
||||||
"/UrlEncode[[Test]]/UrlEncode[[someval1]]/UrlEncode[[someval2]]UrlEncode[[.]]UrlEncode[[someval3]]"
|
"/Test/someval1/someval2.someval3"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Test/{val1}/{val2}.{val3?}",
|
"Test/{val1}/{val2}.{val3?}",
|
||||||
new RouteValueDictionary(new {val1 = "someval1", val2 = "someval2"}),
|
new RouteValueDictionary(new {val1 = "someval1", val2 = "someval2"}),
|
||||||
new RouteValueDictionary(new {val3 = "someval3a"}),
|
new RouteValueDictionary(new {val3 = "someval3a"}),
|
||||||
new RouteValueDictionary(new {val3 = "someval3v"}),
|
new RouteValueDictionary(new {val3 = "someval3v"}),
|
||||||
"/UrlEncode[[Test]]/UrlEncode[[someval1]]/UrlEncode[[someval2]]UrlEncode[[.]]UrlEncode[[someval3v]]"
|
"/Test/someval1/someval2.someval3v"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Test/{val1}/{val2}.{val3?}",
|
"Test/{val1}/{val2}.{val3?}",
|
||||||
new RouteValueDictionary(new {val1 = "someval1", val2 = "someval2"}),
|
new RouteValueDictionary(new {val1 = "someval1", val2 = "someval2"}),
|
||||||
new RouteValueDictionary(new {val3 = "someval3a"}),
|
new RouteValueDictionary(new {val3 = "someval3a"}),
|
||||||
new RouteValueDictionary(),
|
new RouteValueDictionary(),
|
||||||
"/UrlEncode[[Test]]/UrlEncode[[someval1]]/UrlEncode[[someval2]]UrlEncode[[.]]UrlEncode[[someval3a]]"
|
"/Test/someval1/someval2.someval3a"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Test/{val1}/{val2}.{val3?}",
|
"Test/{val1}/{val2}.{val3?}",
|
||||||
new RouteValueDictionary(new {val1 = "someval1", val2 = "someval2"}),
|
new RouteValueDictionary(new {val1 = "someval1", val2 = "someval2"}),
|
||||||
new RouteValueDictionary(),
|
new RouteValueDictionary(),
|
||||||
new RouteValueDictionary(new {val3 = "someval3v"}),
|
new RouteValueDictionary(new {val3 = "someval3v"}),
|
||||||
"/UrlEncode[[Test]]/UrlEncode[[someval1]]/UrlEncode[[someval2]]UrlEncode[[.]]UrlEncode[[someval3v]]"
|
"/Test/someval1/someval2.someval3v"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Test/{val1}/{val2}.{val3?}",
|
"Test/{val1}/{val2}.{val3?}",
|
||||||
new RouteValueDictionary(new {val1 = "someval1", val2 = "someval2"}),
|
new RouteValueDictionary(new {val1 = "someval1", val2 = "someval2"}),
|
||||||
new RouteValueDictionary(),
|
new RouteValueDictionary(),
|
||||||
new RouteValueDictionary(),
|
new RouteValueDictionary(),
|
||||||
"/UrlEncode[[Test]]/UrlEncode[[someval1]]/UrlEncode[[someval2]]"
|
"/Test/someval1/someval2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Test/{val1}.{val2}.{val3}.{val4?}",
|
"Test/{val1}.{val2}.{val3}.{val4?}",
|
||||||
new RouteValueDictionary(new {val1 = "someval1", val2 = "someval2" }),
|
new RouteValueDictionary(new {val1 = "someval1", val2 = "someval2" }),
|
||||||
new RouteValueDictionary(),
|
new RouteValueDictionary(),
|
||||||
new RouteValueDictionary(new {val4 = "someval4", val3 = "someval3" }),
|
new RouteValueDictionary(new {val4 = "someval4", val3 = "someval3" }),
|
||||||
"/UrlEncode[[Test]]/UrlEncode[[someval1]]UrlEncode[[.]]UrlEncode[[someval2]]UrlEncode[[.]]"
|
"/Test/someval1.someval2."
|
||||||
+ "UrlEncode[[someval3]]UrlEncode[[.]]UrlEncode[[someval4]]"
|
+ "someval3.someval4"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Test/{val1}.{val2}.{val3}.{val4?}",
|
"Test/{val1}.{val2}.{val3}.{val4?}",
|
||||||
new RouteValueDictionary(new {val1 = "someval1", val2 = "someval2" }),
|
new RouteValueDictionary(new {val1 = "someval1", val2 = "someval2" }),
|
||||||
new RouteValueDictionary(),
|
new RouteValueDictionary(),
|
||||||
new RouteValueDictionary(new {val3 = "someval3" }),
|
new RouteValueDictionary(new {val3 = "someval3" }),
|
||||||
"/UrlEncode[[Test]]/UrlEncode[[someval1]]UrlEncode[[.]]UrlEncode[[someval2]]UrlEncode[[.]]"
|
"/Test/someval1.someval2."
|
||||||
+ "UrlEncode[[someval3]]"
|
+ "someval3"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Test/.{val2?}",
|
"Test/.{val2?}",
|
||||||
new RouteValueDictionary(new { }),
|
new RouteValueDictionary(new { }),
|
||||||
new RouteValueDictionary(),
|
new RouteValueDictionary(),
|
||||||
new RouteValueDictionary(new {val2 = "someval2" }),
|
new RouteValueDictionary(new {val2 = "someval2" }),
|
||||||
"/UrlEncode[[Test]]/UrlEncode[[.]]UrlEncode[[someval2]]"
|
"/Test/.someval2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Test/{val1}.{val2}",
|
"Test/{val1}.{val2}",
|
||||||
new RouteValueDictionary(new {val1 = "someval1", val2 = "someval2" }),
|
new RouteValueDictionary(new {val1 = "someval1", val2 = "someval2" }),
|
||||||
new RouteValueDictionary(),
|
new RouteValueDictionary(),
|
||||||
new RouteValueDictionary(new {val3 = "someval3" }),
|
new RouteValueDictionary(new {val3 = "someval3" }),
|
||||||
"/UrlEncode[[Test]]/UrlEncode[[someval1]]UrlEncode[[.]]UrlEncode[[someval2]]?" +
|
"/Test/someval1.someval2?" +
|
||||||
"UrlEncode[[val3]]=UrlEncode[[someval3]]"
|
"val3=someval3"
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -266,10 +264,9 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
string expected)
|
string expected)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var encoder = new UrlTestEncoder();
|
|
||||||
var binder = new TemplateBinder(
|
var binder = new TemplateBinder(
|
||||||
encoder,
|
UrlEncoder.Default,
|
||||||
new DefaultObjectPoolProvider().Create(new UriBuilderContextPooledObjectPolicy(encoder)),
|
new DefaultObjectPoolProvider().Create(new UriBuilderContextPooledObjectPolicy()),
|
||||||
TemplateParser.Parse(template),
|
TemplateParser.Parse(template),
|
||||||
defaults);
|
defaults);
|
||||||
|
|
||||||
|
|
@ -307,7 +304,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
null,
|
null,
|
||||||
new RouteValueDictionary(new { lang = "en", region = "US" }),
|
new RouteValueDictionary(new { lang = "en", region = "US" }),
|
||||||
new RouteValueDictionary(new { lang = "xx", region = "yy" }),
|
new RouteValueDictionary(new { lang = "xx", region = "yy" }),
|
||||||
"/UrlEncode[[language]]/UrlEncode[[a]]UrlEncode[[xx]]UrlEncode[[-]]UrlEncode[[yy]]UrlEncode[[a]]");
|
"/language/axx-yya");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -340,7 +337,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
null,
|
null,
|
||||||
new RouteValueDictionary(new { lang = "en" }),
|
new RouteValueDictionary(new { lang = "en" }),
|
||||||
new RouteValueDictionary(new { lang = "xx" }),
|
new RouteValueDictionary(new { lang = "xx" }),
|
||||||
"/UrlEncode[[language]]/UrlEncode[[xx]]");
|
"/language/xx");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -351,7 +348,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
null,
|
null,
|
||||||
new RouteValueDictionary(new { lang = "en" }),
|
new RouteValueDictionary(new { lang = "en" }),
|
||||||
new RouteValueDictionary(new { lang = "xx" }),
|
new RouteValueDictionary(new { lang = "xx" }),
|
||||||
"/UrlEncode[[language]]/UrlEncode[[xx]]UrlEncode[[-]]");
|
"/language/xx-");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -362,7 +359,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
null,
|
null,
|
||||||
new RouteValueDictionary(new { lang = "en" }),
|
new RouteValueDictionary(new { lang = "en" }),
|
||||||
new RouteValueDictionary(new { lang = "xx" }),
|
new RouteValueDictionary(new { lang = "xx" }),
|
||||||
"/UrlEncode[[language]]/UrlEncode[[a]]UrlEncode[[xx]]");
|
"/language/axx");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -373,7 +370,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
null,
|
null,
|
||||||
new RouteValueDictionary(new { lang = "en" }),
|
new RouteValueDictionary(new { lang = "en" }),
|
||||||
new RouteValueDictionary(new { lang = "xx" }),
|
new RouteValueDictionary(new { lang = "xx" }),
|
||||||
"/UrlEncode[[language]]/UrlEncode[[a]]UrlEncode[[xx]]UrlEncode[[a]]");
|
"/language/axxa");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -384,7 +381,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
new RouteValueDictionary(new { action = "Index", id = (string)null }),
|
new RouteValueDictionary(new { action = "Index", id = (string)null }),
|
||||||
new RouteValueDictionary(new { controller = "home", action = "list", id = (string)null }),
|
new RouteValueDictionary(new { controller = "home", action = "list", id = (string)null }),
|
||||||
new RouteValueDictionary(new { controller = "products" }),
|
new RouteValueDictionary(new { controller = "products" }),
|
||||||
"/UrlEncode[[products]]UrlEncode[[.mvc]]");
|
"/products.mvc");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -395,7 +392,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
new RouteValueDictionary(new { lang = "xx", region = "yy" }),
|
new RouteValueDictionary(new { lang = "xx", region = "yy" }),
|
||||||
new RouteValueDictionary(new { lang = "en", region = "US" }),
|
new RouteValueDictionary(new { lang = "en", region = "US" }),
|
||||||
new RouteValueDictionary(new { lang = "zz" }),
|
new RouteValueDictionary(new { lang = "zz" }),
|
||||||
"/UrlEncode[[language]]/UrlEncode[[zz]]UrlEncode[[-]]UrlEncode[[yy]]");
|
"/language/zz-yy");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -407,7 +404,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
new RouteValueDictionary(new { id = "defaultid" }),
|
new RouteValueDictionary(new { id = "defaultid" }),
|
||||||
new RouteValueDictionary(new { controller = "home", action = "oldaction" }),
|
new RouteValueDictionary(new { controller = "home", action = "oldaction" }),
|
||||||
new RouteValueDictionary(new { action = "newaction" }),
|
new RouteValueDictionary(new { action = "newaction" }),
|
||||||
"/UrlEncode[[home]]/UrlEncode[[newaction]]");
|
"/home/newaction");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -440,7 +437,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
null,
|
null,
|
||||||
new RouteValueDictionary(new { }),
|
new RouteValueDictionary(new { }),
|
||||||
new RouteValueDictionary(new { controller = "home" }),
|
new RouteValueDictionary(new { controller = "home" }),
|
||||||
"/UrlEncode[[foo]]/UrlEncode[[home]]");
|
"/foo/home");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -452,7 +449,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
new RouteValueDictionary(new { id = (string)null }),
|
new RouteValueDictionary(new { id = (string)null }),
|
||||||
new RouteValueDictionary(new { controller = "home", action = "oldaction", id = (string)null }),
|
new RouteValueDictionary(new { controller = "home", action = "oldaction", id = (string)null }),
|
||||||
new RouteValueDictionary(new { action = "newaction" }),
|
new RouteValueDictionary(new { action = "newaction" }),
|
||||||
"/UrlEncode[[home]]/UrlEncode[[newaction]]");
|
"/home/newaction");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -463,7 +460,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
new RouteValueDictionary(new { language = "en", locale = "US" }),
|
new RouteValueDictionary(new { language = "en", locale = "US" }),
|
||||||
new RouteValueDictionary(),
|
new RouteValueDictionary(),
|
||||||
new RouteValueDictionary(new { controller = "Orders" }),
|
new RouteValueDictionary(new { controller = "Orders" }),
|
||||||
"/UrlEncode[[Orders]]/UrlEncode[[en]]UrlEncode[[-]]UrlEncode[[US]]");
|
"/Orders/en-US");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -474,7 +471,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
new RouteValueDictionary(new { action = "Index", id = "" }),
|
new RouteValueDictionary(new { action = "Index", id = "" }),
|
||||||
new RouteValueDictionary(new { controller = "Home", action = "Index", id = "" }),
|
new RouteValueDictionary(new { controller = "Home", action = "Index", id = "" }),
|
||||||
new RouteValueDictionary(new { controller = "Home", action = "TestAction", id = "1", format = (string)null }),
|
new RouteValueDictionary(new { controller = "Home", action = "TestAction", id = "1", format = (string)null }),
|
||||||
"/UrlEncode[[Home]]UrlEncode[[.mvc]]/UrlEncode[[TestAction]]/UrlEncode[[1]]");
|
"/Home.mvc/TestAction/1");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -507,7 +504,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
new { p2 = "d2", p3 = "d3" },
|
new { p2 = "d2", p3 = "d3" },
|
||||||
new { p1 = "v1", },
|
new { p1 = "v1", },
|
||||||
new { p2 = "", p3 = "" },
|
new { p2 = "", p3 = "" },
|
||||||
"/UrlEncode[[v1]]");
|
"/v1");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -518,7 +515,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
new { action = "Index", id = (string)null },
|
new { action = "Index", id = (string)null },
|
||||||
new { controller = "orig", action = "init", id = "123" },
|
new { controller = "orig", action = "init", id = "123" },
|
||||||
new { action = "new", },
|
new { action = "new", },
|
||||||
"/UrlEncode[[orig]]/UrlEncode[[new]]");
|
"/orig/new");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -529,8 +526,8 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
new { year = 1995, occasion = "Christmas", action = "Play", SafeParam = "SafeParamValue" },
|
new { year = 1995, occasion = "Christmas", action = "Play", SafeParam = "SafeParamValue" },
|
||||||
new { controller = "UrlRouting", action = "Play", category = "Photos", year = "2008", occasion = "Easter", SafeParam = "SafeParamValue" },
|
new { controller = "UrlRouting", action = "Play", category = "Photos", year = "2008", occasion = "Easter", SafeParam = "SafeParamValue" },
|
||||||
new { year = (string)null, occasion = "Hola" },
|
new { year = (string)null, occasion = "Hola" },
|
||||||
"/UrlEncode[[UrlGeneration1]]/UrlEncode[[UrlRouting]]UrlEncode[[.mvc]]/UrlEncode[[Play]]/"
|
"/UrlGeneration1/UrlRouting.mvc/Play/"
|
||||||
+ "UrlEncode[[Photos]]/UrlEncode[[1995]]/UrlEncode[[Hola]]");
|
+ "Photos/1995/Hola");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -553,8 +550,8 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
new RouteValueDictionary(new { year = 1995, occasion = "Christmas", action = "Play", SafeParam = "SafeParamValue" }),
|
new RouteValueDictionary(new { year = 1995, occasion = "Christmas", action = "Play", SafeParam = "SafeParamValue" }),
|
||||||
ambientValues,
|
ambientValues,
|
||||||
values,
|
values,
|
||||||
"/UrlEncode[[UrlGeneration1]]/UrlEncode[[UrlRouting]]UrlEncode[[.mvc]]/"
|
"/UrlGeneration1/UrlRouting.mvc/"
|
||||||
+ "UrlEncode[[Play]]/UrlEncode[[Photos]]/UrlEncode[[1995]]/UrlEncode[[Hola]]");
|
+ "Play/Photos/1995/Hola");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -576,7 +573,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
new RouteValueDictionary(new { action = "Default" }),
|
new RouteValueDictionary(new { action = "Default" }),
|
||||||
ambientValues,
|
ambientValues,
|
||||||
values,
|
values,
|
||||||
"/UrlEncode[[subtest]]UrlEncode[[.mvc]]/UrlEncode[[Default]]/UrlEncode[[b]]");
|
"/subtest.mvc/Default/b");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -594,8 +591,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
new RouteValueDictionary(new { controller = "Home" }),
|
new RouteValueDictionary(new { controller = "Home" }),
|
||||||
new RouteValueDictionary(new { controller = "home", action = "Index", id = (string)null }),
|
new RouteValueDictionary(new { controller = "home", action = "Index", id = (string)null }),
|
||||||
values,
|
values,
|
||||||
"/%23;%3F%3A@%26%3D%2B$,.mvc/showcategory/123?so%3Frt=de%3Fsc&maxPrice=100",
|
"/%23;%3F%3A@%26%3D%2B$,.mvc/showcategory/123?so%3Frt=de%3Fsc&maxPrice=100");
|
||||||
UrlEncoder.Default);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -609,8 +605,8 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
new RouteValueDictionary(new { controller = "Home" }),
|
new RouteValueDictionary(new { controller = "Home" }),
|
||||||
new RouteValueDictionary(new { controller = "home", action = "Index", id = (string)null }),
|
new RouteValueDictionary(new { controller = "home", action = "Index", id = (string)null }),
|
||||||
values,
|
values,
|
||||||
"/UrlEncode[[products]]UrlEncode[[.mvc]]/UrlEncode[[showcategory]]/UrlEncode[[123]]" +
|
"/products.mvc/showcategory/123" +
|
||||||
"?UrlEncode[[so?rt]]=UrlEncode[[de?sc]]&UrlEncode[[maxPrice]]=UrlEncode[[100]]");
|
"?so%3Frt=de%3Fsc&maxPrice=100");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -630,8 +626,8 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
maxPrice = 100,
|
maxPrice = 100,
|
||||||
custom = "customValue"
|
custom = "customValue"
|
||||||
}),
|
}),
|
||||||
"/UrlEncode[[products]]UrlEncode[[.mvc]]/UrlEncode[[showcategory]]/UrlEncode[[123]]" +
|
"/products.mvc/showcategory/123" +
|
||||||
"?UrlEncode[[sort]]=UrlEncode[[desc]]&UrlEncode[[maxPrice]]=UrlEncode[[100]]");
|
"?sort=desc&maxPrice=100");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -642,8 +638,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
null,
|
null,
|
||||||
new RouteValueDictionary(new { controller = "ho%me", action = "li st" }),
|
new RouteValueDictionary(new { controller = "ho%me", action = "li st" }),
|
||||||
new RouteValueDictionary(),
|
new RouteValueDictionary(),
|
||||||
"/bl%25og/ho%25me/he%20llo/li%20st",
|
"/bl%25og/ho%25me/he%20llo/li%20st");
|
||||||
UrlEncoder.Default);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -654,8 +649,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
null,
|
null,
|
||||||
new RouteValueDictionary(new { controller = "/home", action = "/my/index" }),
|
new RouteValueDictionary(new { controller = "/home", action = "/my/index" }),
|
||||||
new RouteValueDictionary(),
|
new RouteValueDictionary(),
|
||||||
"/home/%2Fmy%2Findex",
|
"/home/%2Fmy%2Findex");
|
||||||
UrlEncoder.Default);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -666,7 +660,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
new RouteValueDictionary(new { id = "defaultid" }),
|
new RouteValueDictionary(new { id = "defaultid" }),
|
||||||
new RouteValueDictionary(new { p1 = "v1" }),
|
new RouteValueDictionary(new { p1 = "v1" }),
|
||||||
new RouteValueDictionary(new { p2 = "v2a/v2b" }),
|
new RouteValueDictionary(new { p2 = "v2a/v2b" }),
|
||||||
"/UrlEncode[[v1]]/UrlEncode[[v2a/v2b]]");
|
"/v1/v2a%2Fv2b");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -677,7 +671,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
new RouteValueDictionary(new { id = "defaultid" }),
|
new RouteValueDictionary(new { id = "defaultid" }),
|
||||||
new RouteValueDictionary(new { p1 = "v1" }),
|
new RouteValueDictionary(new { p1 = "v1" }),
|
||||||
new RouteValueDictionary(new { p2 = "" }),
|
new RouteValueDictionary(new { p2 = "" }),
|
||||||
"/UrlEncode[[v1]]");
|
"/v1");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -688,7 +682,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
new RouteValueDictionary(new { id = "defaultid" }),
|
new RouteValueDictionary(new { id = "defaultid" }),
|
||||||
new RouteValueDictionary(new { p1 = "v1" }),
|
new RouteValueDictionary(new { p1 = "v1" }),
|
||||||
new RouteValueDictionary(new { p2 = (string)null }),
|
new RouteValueDictionary(new { p2 = (string)null }),
|
||||||
"/UrlEncode[[v1]]");
|
"/v1");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -699,7 +693,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
new RouteValueDictionary(new { }),
|
new RouteValueDictionary(new { }),
|
||||||
"/UrlEncode[[foo]]");
|
"/foo");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -710,7 +704,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
new RouteValueDictionary(new { }),
|
new RouteValueDictionary(new { }),
|
||||||
"/UrlEncode[[foo]]");
|
"/foo");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -718,10 +712,9 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var template = "{area?}/{controller=Home}/{action=Index}/{id?}";
|
var template = "{area?}/{controller=Home}/{action=Index}/{id?}";
|
||||||
var encoder = new UrlTestEncoder();
|
|
||||||
var binder = new TemplateBinder(
|
var binder = new TemplateBinder(
|
||||||
new UrlTestEncoder(),
|
UrlEncoder.Default,
|
||||||
new DefaultObjectPoolProvider().Create(new UriBuilderContextPooledObjectPolicy(encoder)),
|
new DefaultObjectPoolProvider().Create(new UriBuilderContextPooledObjectPolicy()),
|
||||||
TemplateParser.Parse(template),
|
TemplateParser.Parse(template),
|
||||||
defaults: null);
|
defaults: null);
|
||||||
var ambientValues = new RouteValueDictionary();
|
var ambientValues = new RouteValueDictionary();
|
||||||
|
|
@ -1145,15 +1138,12 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
RouteValueDictionary defaults,
|
RouteValueDictionary defaults,
|
||||||
RouteValueDictionary ambientValues,
|
RouteValueDictionary ambientValues,
|
||||||
RouteValueDictionary values,
|
RouteValueDictionary values,
|
||||||
string expected,
|
string expected)
|
||||||
UrlEncoder encoder = null)
|
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
encoder = encoder ?? new UrlTestEncoder();
|
|
||||||
|
|
||||||
var binder = new TemplateBinder(
|
var binder = new TemplateBinder(
|
||||||
encoder,
|
UrlEncoder.Default,
|
||||||
new DefaultObjectPoolProvider().Create(new UriBuilderContextPooledObjectPolicy(encoder)),
|
new DefaultObjectPoolProvider().Create(new UriBuilderContextPooledObjectPolicy()),
|
||||||
TemplateParser.Parse(template),
|
TemplateParser.Parse(template),
|
||||||
defaults);
|
defaults);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -244,13 +244,12 @@ namespace Microsoft.AspNetCore.Routing.Tree
|
||||||
private static TreeRouteBuilder CreateBuilder()
|
private static TreeRouteBuilder CreateBuilder()
|
||||||
{
|
{
|
||||||
var objectPoolProvider = new DefaultObjectPoolProvider();
|
var objectPoolProvider = new DefaultObjectPoolProvider();
|
||||||
var objectPolicy = new UriBuilderContextPooledObjectPolicy(UrlEncoder.Default);
|
var objectPolicy = new UriBuilderContextPooledObjectPolicy();
|
||||||
var objectPool = objectPoolProvider.Create(objectPolicy);
|
var objectPool = objectPoolProvider.Create(objectPolicy);
|
||||||
|
|
||||||
var constraintResolver = GetInlineConstraintResolver();
|
var constraintResolver = GetInlineConstraintResolver();
|
||||||
var builder = new TreeRouteBuilder(
|
var builder = new TreeRouteBuilder(
|
||||||
NullLoggerFactory.Instance,
|
NullLoggerFactory.Instance,
|
||||||
UrlEncoder.Default,
|
|
||||||
objectPool,
|
objectPool,
|
||||||
constraintResolver);
|
constraintResolver);
|
||||||
return builder;
|
return builder;
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
using Microsoft.Extensions.ObjectPool;
|
using Microsoft.Extensions.ObjectPool;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Microsoft.Extensions.WebEncoders.Testing;
|
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -23,9 +22,72 @@ namespace Microsoft.AspNetCore.Routing.Tree
|
||||||
{
|
{
|
||||||
private static readonly RequestDelegate NullHandler = (c) => Task.FromResult(0);
|
private static readonly RequestDelegate NullHandler = (c) => Task.FromResult(0);
|
||||||
|
|
||||||
private static UrlEncoder Encoder = UrlTestEncoder.Default;
|
|
||||||
private static ObjectPool<UriBuildingContext> Pool = new DefaultObjectPoolProvider().Create(
|
private static ObjectPool<UriBuildingContext> Pool = new DefaultObjectPoolProvider().Create(
|
||||||
new UriBuilderContextPooledObjectPolicy(Encoder));
|
new UriBuilderContextPooledObjectPolicy());
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task TreeRouter_RouteAsync_MatchesCatchAllRoutesWithDefaults_UsingObsoleteConstructo()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var routes = new[] {
|
||||||
|
"{parameter1=1}/{parameter2=2}/{parameter3=3}/{*parameter4=4}",
|
||||||
|
};
|
||||||
|
var url = "/a/b/c";
|
||||||
|
var routeValues = new[] { "a", "b", "c", "4" };
|
||||||
|
|
||||||
|
var expectedRouteGroup = CreateRouteGroup(0, "{parameter1=1}/{parameter2=2}/{parameter3=3}/{*parameter4=4}");
|
||||||
|
var routeValueKeys = new[] { "parameter1", "parameter2", "parameter3", "parameter4" };
|
||||||
|
var expectedRouteValues = new RouteValueDictionary();
|
||||||
|
for (int i = 0; i < routeValueKeys.Length; i++)
|
||||||
|
{
|
||||||
|
expectedRouteValues.Add(routeValueKeys[i], routeValues[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
var builder = CreateBuilderUsingObsoleteConstructor();
|
||||||
|
|
||||||
|
// We setup the route entries in reverse order of precedence to ensure that when we
|
||||||
|
// try to route the request, the route with a higher precedence gets tried first.
|
||||||
|
foreach (var template in routes.Reverse())
|
||||||
|
{
|
||||||
|
MapInboundEntry(builder, template);
|
||||||
|
}
|
||||||
|
|
||||||
|
var route = builder.Build();
|
||||||
|
|
||||||
|
var context = CreateRouteContext(url);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await route.RouteAsync(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expectedRouteGroup, context.RouteData.Values["test_route_group"]);
|
||||||
|
foreach (var entry in expectedRouteValues)
|
||||||
|
{
|
||||||
|
var data = Assert.Single(context.RouteData.Values, v => v.Key == entry.Key);
|
||||||
|
Assert.Equal(entry.Value, data.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task TreeRouter_RouteAsync_DoesNotMatchRoutesWithIntermediateDefaultRouteValues_UsingObsoleteConstructor()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var url = "/a/b";
|
||||||
|
|
||||||
|
var builder = CreateBuilderUsingObsoleteConstructor();
|
||||||
|
|
||||||
|
MapInboundEntry(builder, "a/b/{parameter3=3}/d");
|
||||||
|
|
||||||
|
var route = builder.Build();
|
||||||
|
|
||||||
|
var context = CreateRouteContext(url);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await route.RouteAsync(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Null(context.Handler);
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("template/5", "template/{parameter:int}")]
|
[InlineData("template/5", "template/{parameter:int}")]
|
||||||
|
|
@ -1990,15 +2052,31 @@ namespace Microsoft.AspNetCore.Routing.Tree
|
||||||
private static TreeRouteBuilder CreateBuilder()
|
private static TreeRouteBuilder CreateBuilder()
|
||||||
{
|
{
|
||||||
var objectPoolProvider = new DefaultObjectPoolProvider();
|
var objectPoolProvider = new DefaultObjectPoolProvider();
|
||||||
var objectPolicy = new UriBuilderContextPooledObjectPolicy(UrlEncoder.Default);
|
var objectPolicy = new UriBuilderContextPooledObjectPolicy();
|
||||||
var objectPool = objectPoolProvider.Create<UriBuildingContext>(objectPolicy);
|
var objectPool = objectPoolProvider.Create<UriBuildingContext>(objectPolicy);
|
||||||
|
|
||||||
var constraintResolver = CreateConstraintResolver();
|
var constraintResolver = CreateConstraintResolver();
|
||||||
|
var builder = new TreeRouteBuilder(
|
||||||
|
NullLoggerFactory.Instance,
|
||||||
|
objectPool,
|
||||||
|
constraintResolver);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TreeRouteBuilder CreateBuilderUsingObsoleteConstructor()
|
||||||
|
{
|
||||||
|
var objectPoolProvider = new DefaultObjectPoolProvider();
|
||||||
|
var objectPolicy = new UriBuilderContextPooledObjectPolicy();
|
||||||
|
var objectPool = objectPoolProvider.Create<UriBuildingContext>(objectPolicy);
|
||||||
|
|
||||||
|
var constraintResolver = CreateConstraintResolver();
|
||||||
|
#pragma warning disable CS0618 // Type or member is obsolete
|
||||||
var builder = new TreeRouteBuilder(
|
var builder = new TreeRouteBuilder(
|
||||||
NullLoggerFactory.Instance,
|
NullLoggerFactory.Instance,
|
||||||
UrlEncoder.Default,
|
UrlEncoder.Default,
|
||||||
objectPool,
|
objectPool,
|
||||||
constraintResolver);
|
constraintResolver);
|
||||||
|
#pragma warning restore CS0618 // Type or member is obsolete
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue