Merge branch 'merge/release/2.2-to-master'
# Conflicts: # build/dependencies.props
This commit is contained in:
commit
b0cd3f2d7a
|
|
@ -1,4 +1,4 @@
|
|||
Contributing
|
||||
======
|
||||
|
||||
Information on contributing to this repo is in the [Contributing Guide](https://github.com/aspnet/Home/blob/dev/CONTRIBUTING.md) in the Home repo.
|
||||
Information on contributing to this repo is in the [Contributing Guide](https://github.com/aspnet/Home/blob/master/CONTRIBUTING.md) in the Home repo.
|
||||
|
|
|
|||
|
|
@ -4,10 +4,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Core;
|
||||
using Microsoft.AspNetCore.Mvc.Internal;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.Builder
|
||||
{
|
||||
|
|
@ -16,6 +18,9 @@ namespace Microsoft.AspNetCore.Builder
|
|||
/// </summary>
|
||||
public static class MvcApplicationBuilderExtensions
|
||||
{
|
||||
// Property key set in routing package by UseGlobalRouting to indicate middleware is registered
|
||||
private const string GlobalRoutingRegisteredKey = "__GlobalRoutingMiddlewareRegistered";
|
||||
|
||||
/// <summary>
|
||||
/// Adds MVC to the <see cref="IApplicationBuilder"/> request execution pipeline.
|
||||
/// </summary>
|
||||
|
|
@ -79,16 +84,91 @@ namespace Microsoft.AspNetCore.Builder
|
|||
|
||||
VerifyMvcIsRegistered(app);
|
||||
|
||||
var routes = new RouteBuilder(app)
|
||||
var options = app.ApplicationServices.GetRequiredService<IOptions<MvcOptions>>();
|
||||
|
||||
if (options.Value.EnableGlobalRouting)
|
||||
{
|
||||
DefaultHandler = app.ApplicationServices.GetRequiredService<MvcRouteHandler>(),
|
||||
};
|
||||
var mvcEndpointDataSource = app.ApplicationServices
|
||||
.GetRequiredService<IEnumerable<EndpointDataSource>>()
|
||||
.OfType<MvcEndpointDataSource>()
|
||||
.First();
|
||||
var constraintResolver = app.ApplicationServices
|
||||
.GetRequiredService<IInlineConstraintResolver>();
|
||||
|
||||
configureRoutes(routes);
|
||||
var endpointRouteBuilder = new EndpointRouteBuilder(app);
|
||||
|
||||
routes.Routes.Insert(0, AttributeRouting.CreateAttributeMegaRoute(app.ApplicationServices));
|
||||
configureRoutes(endpointRouteBuilder);
|
||||
|
||||
return app.UseRouter(routes.Build());
|
||||
foreach (var router in endpointRouteBuilder.Routes)
|
||||
{
|
||||
// Only accept Microsoft.AspNetCore.Routing.Route when converting to endpoint
|
||||
// Sub-types could have additional customization that we can't knowingly convert
|
||||
if (router is Route route && router.GetType() == typeof(Route))
|
||||
{
|
||||
var endpointInfo = new MvcEndpointInfo(
|
||||
route.Name,
|
||||
route.RouteTemplate,
|
||||
route.Defaults,
|
||||
route.Constraints.ToDictionary(kvp => kvp.Key, kvp => (object)kvp.Value),
|
||||
route.DataTokens,
|
||||
constraintResolver);
|
||||
|
||||
mvcEndpointDataSource.ConventionalEndpointInfos.Add(endpointInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException($"Cannot use '{router.GetType().FullName}' with Global Routing.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!app.Properties.TryGetValue(GlobalRoutingRegisteredKey, out _))
|
||||
{
|
||||
// Matching middleware has not been registered yet
|
||||
// For back-compat register middleware so an endpoint is matched and then immediately used
|
||||
app.UseGlobalRouting();
|
||||
}
|
||||
|
||||
return app.UseEndpoint();
|
||||
}
|
||||
else
|
||||
{
|
||||
var routes = new RouteBuilder(app)
|
||||
{
|
||||
DefaultHandler = app.ApplicationServices.GetRequiredService<MvcRouteHandler>(),
|
||||
};
|
||||
|
||||
configureRoutes(routes);
|
||||
|
||||
routes.Routes.Insert(0, AttributeRouting.CreateAttributeMegaRoute(app.ApplicationServices));
|
||||
|
||||
return app.UseRouter(routes.Build());
|
||||
}
|
||||
}
|
||||
|
||||
private class EndpointRouteBuilder : IRouteBuilder
|
||||
{
|
||||
public EndpointRouteBuilder(IApplicationBuilder applicationBuilder)
|
||||
{
|
||||
ApplicationBuilder = applicationBuilder;
|
||||
Routes = new List<IRouter>();
|
||||
DefaultHandler = NullRouter.Instance;
|
||||
}
|
||||
|
||||
public IApplicationBuilder ApplicationBuilder { get; }
|
||||
|
||||
public IRouter DefaultHandler { get; set; }
|
||||
|
||||
public IServiceProvider ServiceProvider
|
||||
{
|
||||
get { return ApplicationBuilder.ApplicationServices; }
|
||||
}
|
||||
|
||||
public IList<IRouter> Routes { get; }
|
||||
|
||||
public IRouter Build()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static IApplicationBuilder UseMvcWithEndpoint(
|
||||
|
|
|
|||
|
|
@ -94,10 +94,13 @@ namespace Microsoft.AspNetCore.Builder
|
|||
{
|
||||
if (parameter.DefaultValue != null)
|
||||
{
|
||||
if (result.ContainsKey(parameter.Name))
|
||||
if (result.TryGetValue(parameter.Name, out var value))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
string.Format(CultureInfo.CurrentCulture, "The route parameter '{0}' has both an inline default value and an explicit default value specified. A route parameter cannot contain an inline default value when a default value is specified explicitly. Consider removing one of them.", parameter.Name));
|
||||
if (!object.Equals(value, parameter.DefaultValue))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
string.Format(CultureInfo.CurrentCulture, "The route parameter '{0}' has both an inline default value and an explicit default value specified. A route parameter cannot contain an inline default value when a default value is specified explicitly. Consider removing one of them.", parameter.Name));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,6 +32,11 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
values[nameof(MvcOptions.SuppressBindingUndefinedValueToEnumType)] = true;
|
||||
}
|
||||
|
||||
if (Version >= CompatibilityVersion.Version_2_2)
|
||||
{
|
||||
values[nameof(MvcOptions.EnableGlobalRouting)] = true;
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
|||
//
|
||||
// REVIEW: This is really ugly
|
||||
if (endpointInfo.Constraints.TryGetValue(routeKey, out var constraint)
|
||||
&& !constraint.Match(new DefaultHttpContext() { RequestServices = _serviceProvider }, new DummyRouter(), routeKey, new RouteValueDictionary(action.RouteValues), RouteDirection.IncomingRequest))
|
||||
&& !constraint.Match(new DefaultHttpContext() { RequestServices = _serviceProvider }, NullRouter.Instance, routeKey, new RouteValueDictionary(action.RouteValues), RouteDirection.IncomingRequest))
|
||||
{
|
||||
// Did not match constraint
|
||||
return false;
|
||||
|
|
@ -260,19 +260,6 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
|||
return false;
|
||||
}
|
||||
|
||||
private class DummyRouter : IRouter
|
||||
{
|
||||
public VirtualPathData GetVirtualPath(VirtualPathContext context)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public Task RouteAsync(RouteContext context)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
private MatcherEndpoint CreateEndpoint(
|
||||
ActionDescriptor action,
|
||||
string routeName,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
// 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.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Internal
|
||||
{
|
||||
internal class NullRouter : IRouter
|
||||
{
|
||||
public static IRouter Instance = new NullRouter();
|
||||
|
||||
private NullRouter()
|
||||
{
|
||||
}
|
||||
|
||||
public VirtualPathData GetVirtualPath(VirtualPathContext context)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public Task RouteAsync(RouteContext context)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -30,6 +30,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
private readonly CompatibilitySwitch<bool> _allowValidatingTopLevelNodes;
|
||||
private readonly CompatibilitySwitch<InputFormatterExceptionPolicy> _inputFormatterExceptionPolicy;
|
||||
private readonly CompatibilitySwitch<bool> _suppressBindingUndefinedValueToEnumType;
|
||||
private readonly CompatibilitySwitch<bool> _enableGlobalRouting;
|
||||
private readonly ICompatibilitySwitch[] _switches;
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -54,6 +55,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
_allowValidatingTopLevelNodes = new CompatibilitySwitch<bool>(nameof(AllowValidatingTopLevelNodes));
|
||||
_inputFormatterExceptionPolicy = new CompatibilitySwitch<InputFormatterExceptionPolicy>(nameof(InputFormatterExceptionPolicy), InputFormatterExceptionPolicy.AllExceptions);
|
||||
_suppressBindingUndefinedValueToEnumType = new CompatibilitySwitch<bool>(nameof(SuppressBindingUndefinedValueToEnumType));
|
||||
_enableGlobalRouting = new CompatibilitySwitch<bool>(nameof(EnableGlobalRouting));
|
||||
|
||||
_switches = new ICompatibilitySwitch[]
|
||||
{
|
||||
|
|
@ -62,9 +64,17 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
_allowValidatingTopLevelNodes,
|
||||
_inputFormatterExceptionPolicy,
|
||||
_suppressBindingUndefinedValueToEnumType,
|
||||
_enableGlobalRouting,
|
||||
};
|
||||
}
|
||||
|
||||
// REVIEW: Add documentation
|
||||
public bool EnableGlobalRouting
|
||||
{
|
||||
get => _enableGlobalRouting.Value;
|
||||
set => _enableGlobalRouting.Value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the flag which decides whether body model binding (for example, on an
|
||||
/// action method parameter with <see cref="FromBodyAttribute"/>) should treat empty
|
||||
|
|
|
|||
|
|
@ -16,6 +16,83 @@ namespace Microsoft.AspNetCore.Mvc.Routing
|
|||
{
|
||||
public class GlobalRoutingUrlHelperTest : UrlHelperTestBase
|
||||
{
|
||||
[Fact]
|
||||
public void RouteUrl_WithRouteName_GeneratesUrl_UsingDefaults()
|
||||
{
|
||||
// Arrange
|
||||
var endpoint1 = CreateEndpoint(
|
||||
"api/orders/{id}",
|
||||
defaults: new { controller = "Orders", action = "GetById" },
|
||||
requiredValues: new { controller = "Orders", action = "GetById" },
|
||||
routeName: "OrdersApi");
|
||||
var endpoint2 = CreateEndpoint(
|
||||
"api/orders",
|
||||
defaults: new { controller = "Orders", action = "GetAll" },
|
||||
requiredValues: new { controller = "Orders", action = "GetAll" },
|
||||
routeName: "OrdersApi");
|
||||
var urlHelper = CreateUrlHelper(new[] { endpoint1, endpoint2 });
|
||||
|
||||
// Act
|
||||
var url = urlHelper.RouteUrl(
|
||||
routeName: "OrdersApi",
|
||||
values: new { });
|
||||
|
||||
// Assert
|
||||
Assert.Equal("/" + endpoint2.RoutePattern.RawText, url);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RouteUrl_WithRouteName_UsesAmbientValues()
|
||||
{
|
||||
// Arrange
|
||||
var endpoint1 = CreateEndpoint(
|
||||
"api/orders/{id}",
|
||||
defaults: new { controller = "Orders", action = "GetById" },
|
||||
requiredValues: new { controller = "Orders", action = "GetById" },
|
||||
routeName: "OrdersApi");
|
||||
var endpoint2 = CreateEndpoint(
|
||||
"api/orders",
|
||||
defaults: new { controller = "Orders", action = "GetAll" },
|
||||
requiredValues: new { controller = "Orders", action = "GetAll" },
|
||||
routeName: "OrdersApi");
|
||||
var urlHelper = CreateUrlHelper(new[] { endpoint1, endpoint2 });
|
||||
urlHelper.ActionContext.RouteData.Values["id"] = "500";
|
||||
|
||||
// Act
|
||||
var url = urlHelper.RouteUrl(
|
||||
routeName: "OrdersApi",
|
||||
values: new { });
|
||||
|
||||
// Assert
|
||||
Assert.Equal("/api/orders/500", url);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RouteUrl_WithRouteName_UsesSuppliedValue_OverridingAmbientValue()
|
||||
{
|
||||
// Arrange
|
||||
var endpoint1 = CreateEndpoint(
|
||||
"api/orders/{id}",
|
||||
defaults: new { controller = "Orders", action = "GetById" },
|
||||
requiredValues: new { controller = "Orders", action = "GetById" },
|
||||
routeName: "OrdersApi");
|
||||
var endpoint2 = CreateEndpoint(
|
||||
"api/orders",
|
||||
defaults: new { controller = "Orders", action = "GetAll" },
|
||||
requiredValues: new { controller = "Orders", action = "GetAll" },
|
||||
routeName: "OrdersApi");
|
||||
var urlHelper = CreateUrlHelper(new[] { endpoint1, endpoint2 });
|
||||
urlHelper.ActionContext.RouteData.Values["id"] = "500";
|
||||
|
||||
// Act
|
||||
var url = urlHelper.RouteUrl(
|
||||
routeName: "OrdersApi",
|
||||
values: new { id = "10" });
|
||||
|
||||
// Assert
|
||||
Assert.Equal("/api/orders/10", url);
|
||||
}
|
||||
|
||||
protected override IUrlHelper CreateUrlHelper(string appRoot, string host, string protocol)
|
||||
{
|
||||
return CreateUrlHelper(Enumerable.Empty<MatcherEndpoint>(), appRoot, host, protocol);
|
||||
|
|
@ -84,6 +161,14 @@ namespace Microsoft.AspNetCore.Mvc.Routing
|
|||
return CreateUrlHelper(actionContext);
|
||||
}
|
||||
|
||||
private IUrlHelper CreateUrlHelper(IEnumerable<MatcherEndpoint> endpoints, ActionContext actionContext = null)
|
||||
{
|
||||
var serviceProvider = CreateServices(endpoints);
|
||||
var httpContext = CreateHttpContext(serviceProvider, null, null, "http");
|
||||
actionContext = actionContext ?? CreateActionContext(httpContext);
|
||||
return CreateUrlHelper(actionContext);
|
||||
}
|
||||
|
||||
private IUrlHelper CreateUrlHelper(
|
||||
IEnumerable<MatcherEndpoint> endpoints,
|
||||
string appRoot,
|
||||
|
|
@ -99,33 +184,98 @@ namespace Microsoft.AspNetCore.Mvc.Routing
|
|||
private List<MatcherEndpoint> GetDefaultEndpoints()
|
||||
{
|
||||
var endpoints = new List<MatcherEndpoint>();
|
||||
endpoints.Add(CreateEndpoint(null, "home/newaction/{id}", new { id = "defaultid", controller = "home", action = "newaction" }, 1));
|
||||
endpoints.Add(CreateEndpoint(null, "home/contact/{id}", new { id = "defaultid", controller = "home", action = "contact" }, 2));
|
||||
endpoints.Add(CreateEndpoint(null, "home2/newaction/{id}", new { id = "defaultid", controller = "home2", action = "newaction" }, 3));
|
||||
endpoints.Add(CreateEndpoint(null, "home2/contact/{id}", new { id = "defaultid", controller = "home2", action = "contact" }, 4));
|
||||
endpoints.Add(CreateEndpoint(null, "home3/contact/{id}", new { id = "defaultid", controller = "home3", action = "contact" }, 5));
|
||||
endpoints.Add(CreateEndpoint("namedroute", "named/home/newaction/{id}", new { id = "defaultid", controller = "home", action = "newaction" }, 6));
|
||||
endpoints.Add(CreateEndpoint("namedroute", "named/home2/newaction/{id}", new { id = "defaultid", controller = "home2", action = "newaction" }, 7));
|
||||
endpoints.Add(CreateEndpoint("namedroute", "named/home/contact/{id}", new { id = "defaultid", controller = "home", action = "contact" }, 8));
|
||||
endpoints.Add(CreateEndpoint("MyRouteName", "any/url", new { }, 9));
|
||||
endpoints.Add(
|
||||
CreateEndpoint(
|
||||
"home/newaction/{id}",
|
||||
defaults: new { id = "defaultid", controller = "home", action = "newaction" },
|
||||
requiredValues: new { controller = "home", action = "newaction" },
|
||||
order: 1));
|
||||
endpoints.Add(
|
||||
CreateEndpoint(
|
||||
"home/contact/{id}",
|
||||
defaults: new { id = "defaultid", controller = "home", action = "contact" },
|
||||
requiredValues: new { controller = "home", action = "contact" },
|
||||
order: 2));
|
||||
endpoints.Add(
|
||||
CreateEndpoint(
|
||||
"home2/newaction/{id}",
|
||||
defaults: new { id = "defaultid", controller = "home2", action = "newaction" },
|
||||
requiredValues: new { controller = "home2", action = "newaction" },
|
||||
order: 3));
|
||||
endpoints.Add(
|
||||
CreateEndpoint(
|
||||
"home2/contact/{id}",
|
||||
defaults: new { id = "defaultid", controller = "home2", action = "contact" },
|
||||
requiredValues: new { controller = "home2", action = "contact" },
|
||||
order: 4));
|
||||
endpoints.Add(
|
||||
CreateEndpoint(
|
||||
"home3/contact/{id}",
|
||||
defaults: new { id = "defaultid", controller = "home3", action = "contact" },
|
||||
requiredValues: new { controller = "home3", action = "contact" },
|
||||
order: 5));
|
||||
endpoints.Add(
|
||||
CreateEndpoint(
|
||||
"named/home/newaction/{id}",
|
||||
defaults: new { id = "defaultid", controller = "home", action = "newaction" },
|
||||
requiredValues: new { controller = "home", action = "newaction" },
|
||||
order: 6,
|
||||
routeName: "namedroute"));
|
||||
endpoints.Add(
|
||||
CreateEndpoint(
|
||||
"named/home2/newaction/{id}",
|
||||
defaults: new { id = "defaultid", controller = "home2", action = "newaction" },
|
||||
requiredValues: new { controller = "home2", action = "newaction" },
|
||||
order: 7,
|
||||
routeName: "namedroute"));
|
||||
endpoints.Add(
|
||||
CreateEndpoint(
|
||||
"named/home/contact/{id}",
|
||||
defaults: new { id = "defaultid", controller = "home", action = "contact" },
|
||||
requiredValues: new { controller = "home", action = "contact" },
|
||||
order: 8,
|
||||
routeName: "namedroute"));
|
||||
endpoints.Add(
|
||||
CreateEndpoint(
|
||||
"any/url",
|
||||
defaults: new { },
|
||||
requiredValues: new { },
|
||||
order: 9,
|
||||
routeName: "MyRouteName"));
|
||||
endpoints.Add(
|
||||
CreateEndpoint(
|
||||
"api/orders/{id}",
|
||||
defaults: new { controller = "Orders", action = "GetById" },
|
||||
requiredValues: new { controller = "Orders", action = "GetById" },
|
||||
order: 10,
|
||||
routeName: "OrdersApi"));
|
||||
return endpoints;
|
||||
}
|
||||
|
||||
private MatcherEndpoint CreateEndpoint(string routeName, string template, object defaults, int order)
|
||||
private MatcherEndpoint CreateEndpoint(
|
||||
string template,
|
||||
object defaults = null,
|
||||
object requiredValues = null,
|
||||
int order = 0,
|
||||
string routeName = null,
|
||||
EndpointMetadataCollection metadataCollection = null)
|
||||
{
|
||||
var metadata = EndpointMetadataCollection.Empty;
|
||||
if (!string.IsNullOrEmpty(routeName))
|
||||
if (metadataCollection == null)
|
||||
{
|
||||
metadata = new EndpointMetadataCollection(new[] { new RouteNameMetadata(routeName) });
|
||||
metadataCollection = EndpointMetadataCollection.Empty;
|
||||
if (!string.IsNullOrEmpty(routeName))
|
||||
{
|
||||
metadataCollection = new EndpointMetadataCollection(new[] { new RouteNameMetadata(routeName) });
|
||||
}
|
||||
}
|
||||
|
||||
return new MatcherEndpoint(
|
||||
next => (httpContext) => Task.CompletedTask,
|
||||
RoutePatternFactory.Parse(template, defaults, constraints: null),
|
||||
new RouteValueDictionary(),
|
||||
new RouteValueDictionary(requiredValues),
|
||||
order,
|
||||
metadata,
|
||||
"DisplayName");
|
||||
metadataCollection,
|
||||
null);
|
||||
}
|
||||
|
||||
private IServiceProvider CreateServices(IEnumerable<Endpoint> endpoints)
|
||||
|
|
|
|||
|
|
@ -101,6 +101,11 @@ namespace Microsoft.AspNetCore.Mvc.Routing
|
|||
.Returns<VirtualPathContext>(context => null);
|
||||
routeBuilder.DefaultHandler = target.Object;
|
||||
|
||||
routeBuilder.MapRoute(
|
||||
"OrdersApi",
|
||||
"api/orders/{id}",
|
||||
new RouteValueDictionary(new { controller = "Orders", action = "GetById" }));
|
||||
|
||||
routeBuilder.MapRoute(
|
||||
string.Empty,
|
||||
"{controller}/{action}/{id}",
|
||||
|
|
|
|||
|
|
@ -457,6 +457,36 @@ namespace Microsoft.AspNetCore.Mvc.Routing
|
|||
Assert.Equal("https://pingüino/app/named/home2/newaction/someid", url);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RouteUrl_GeneratesUrl_WithRouteName_UsingDefaultValues_WhenExplicitOrAmbientValues_NotPresent()
|
||||
{
|
||||
// Arrange
|
||||
var urlHelper = CreateUrlHelperWithDefaultRoutes();
|
||||
|
||||
// Act
|
||||
var url = urlHelper.RouteUrl(
|
||||
routeName: "OrdersApi",
|
||||
values: new { id = "500" });
|
||||
|
||||
// Assert
|
||||
Assert.Equal("/app/api/orders/500", url);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RouteUrl_WithRouteName_DoesNotGenerateUrl_WhenRequiredValueForParameter_NotPresent()
|
||||
{
|
||||
// Arrange
|
||||
var urlHelper = CreateUrlHelperWithDefaultRoutes();
|
||||
|
||||
// Act
|
||||
var url = urlHelper.RouteUrl(
|
||||
routeName: "OrdersApi",
|
||||
values: new { });
|
||||
|
||||
// Assert
|
||||
Assert.Null(url);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RouteUrlWithRouteNameAndDictionary()
|
||||
{
|
||||
|
|
@ -922,7 +952,6 @@ namespace Microsoft.AspNetCore.Mvc.Routing
|
|||
Assert.Equal("/b/Store/Checkout", url);
|
||||
}
|
||||
|
||||
|
||||
protected abstract IServiceProvider CreateServices();
|
||||
|
||||
protected abstract IUrlHelper CreateUrlHelper(ActionContext actionContext);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
// 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.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||
{
|
||||
public class ConsumesAttributeGlobalRoutingTests : ConsumesAttributeTestsBase<BasicWebSite.StartupWithGlobalRouting>
|
||||
|
|
@ -9,5 +14,20 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
: base(fixture)
|
||||
{
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async override Task HasEndpointMatch()
|
||||
{
|
||||
// Arrange & Act
|
||||
var response = await Client.GetAsync("http://localhost/Routing/HasEndpointMatch");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
var result = JsonConvert.DeserializeObject<bool>(body);
|
||||
|
||||
Assert.True(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,11 @@
|
|||
// 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.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||
{
|
||||
public class ConsumesAttributeTests : ConsumesAttributeTestsBase<BasicWebSite.Startup>
|
||||
|
|
@ -9,5 +14,20 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
: base(fixture)
|
||||
{
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async override Task HasEndpointMatch()
|
||||
{
|
||||
// Arrange & Act
|
||||
var response = await Client.GetAsync("http://localhost/Routing/HasEndpointMatch");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
var result = JsonConvert.DeserializeObject<bool>(body);
|
||||
|
||||
Assert.False(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -28,6 +28,9 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
|
||||
public HttpClient Client { get; }
|
||||
|
||||
[Fact]
|
||||
public abstract Task HasEndpointMatch();
|
||||
|
||||
[Fact]
|
||||
public async Task NoRequestContentType_SelectsActionWithoutConstraint()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
|
|
@ -16,6 +17,21 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
{
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async override Task HasEndpointMatch()
|
||||
{
|
||||
// Arrange & Act
|
||||
var response = await Client.GetAsync("http://localhost/Routing/HasEndpointMatch");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
var result = JsonConvert.DeserializeObject<bool>(body);
|
||||
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact(Skip = "Link generation issue in global routing. Need to fix - https://github.com/aspnet/Routing/issues/590")]
|
||||
public override Task AttributeRoutedAction_InArea_StaysInArea_ActionDoesntExist()
|
||||
{
|
||||
|
|
@ -61,5 +77,88 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
Array.Empty<string>(),
|
||||
result.Routers);
|
||||
}
|
||||
|
||||
// Global routing exposes HTTP 405s for HTTP method mismatches
|
||||
[Fact]
|
||||
public override async Task ConventionalRoutedController_InArea_ActionBlockedByHttpMethod()
|
||||
{
|
||||
// Arrange & Act
|
||||
var response = await Client.GetAsync("http://localhost/Travel/Flight/BuyTickets");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.MethodNotAllowed, response.StatusCode);
|
||||
}
|
||||
|
||||
// Global routing exposes HTTP 405s for HTTP method mismatches
|
||||
[Fact]
|
||||
public override async Task AttributeRoutedAction_MultipleRouteAttributes_RouteAttributeTemplatesIgnoredForOverrideActions()
|
||||
{
|
||||
// Arrange
|
||||
var url = "http://localhost/api/v1/Maps";
|
||||
|
||||
// Act
|
||||
var response = await Client.SendAsync(new HttpRequestMessage(new HttpMethod("POST"), url));
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.MethodNotAllowed, response.StatusCode);
|
||||
}
|
||||
|
||||
// Global routing exposes HTTP 405s for HTTP method mismatches
|
||||
[Theory]
|
||||
[InlineData("http://localhost/api/v1/Maps/5", "PATCH")]
|
||||
[InlineData("http://localhost/api/v2/Maps/5", "PATCH")]
|
||||
[InlineData("http://localhost/api/v1/Maps/PartialUpdate/5", "PUT")]
|
||||
[InlineData("http://localhost/api/v2/Maps/PartialUpdate/5", "PUT")]
|
||||
public override async Task AttributeRoutedAction_MultipleRouteAttributes_WithMultipleHttpAttributes_RespectsConstraints(
|
||||
string url,
|
||||
string method)
|
||||
{
|
||||
// Arrange
|
||||
var expectedUrl = new Uri(url).AbsolutePath;
|
||||
|
||||
// Act
|
||||
var response = await Client.SendAsync(new HttpRequestMessage(new HttpMethod(method), url));
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.MethodNotAllowed, response.StatusCode);
|
||||
}
|
||||
|
||||
// Global routing exposes HTTP 405s for HTTP method mismatches
|
||||
[Theory]
|
||||
[InlineData("Post", "/Friends")]
|
||||
[InlineData("Put", "/Friends")]
|
||||
[InlineData("Patch", "/Friends")]
|
||||
[InlineData("Options", "/Friends")]
|
||||
[InlineData("Head", "/Friends")]
|
||||
public override async Task AttributeRoutedAction_RejectsRequestsWithWrongMethods_InRoutesWithoutExtraTemplateSegmentsOnTheAction(
|
||||
string method,
|
||||
string url)
|
||||
{
|
||||
// Arrange
|
||||
var request = new HttpRequestMessage(new HttpMethod(method), $"http://localhost{url}");
|
||||
|
||||
// Assert
|
||||
var response = await Client.SendAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.MethodNotAllowed, response.StatusCode);
|
||||
}
|
||||
|
||||
// These verbs don't match
|
||||
[Theory]
|
||||
[InlineData("/Bank/Deposit", "GET")]
|
||||
[InlineData("/Bank/Deposit/5", "DELETE")]
|
||||
[InlineData("/Bank/Withdraw/5", "GET")]
|
||||
public override async Task AttributeRouting_MixedAcceptVerbsAndRoute_Unreachable(string path, string verb)
|
||||
{
|
||||
// Arrange
|
||||
var request = new HttpRequestMessage(new HttpMethod(verb), "http://localhost" + path);
|
||||
|
||||
// Act
|
||||
var response = await Client.SendAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.MethodNotAllowed, response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,11 @@
|
|||
// 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.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||
{
|
||||
public class RequestServicesGlobalRoutingTest : RequestServicesTestBase<BasicWebSite.StartupWithGlobalRouting>
|
||||
|
|
@ -9,5 +14,20 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
: base(fixture)
|
||||
{
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async override Task HasEndpointMatch()
|
||||
{
|
||||
// Arrange & Act
|
||||
var response = await Client.GetAsync("http://localhost/Routing/HasEndpointMatch");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
var result = JsonConvert.DeserializeObject<bool>(body);
|
||||
|
||||
Assert.True(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,11 @@
|
|||
// 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.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||
{
|
||||
public class RequestServicesTest : RequestServicesTestBase<BasicWebSite.Startup>
|
||||
|
|
@ -9,5 +14,20 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
: base(fixture)
|
||||
{
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async override Task HasEndpointMatch()
|
||||
{
|
||||
// Arrange & Act
|
||||
var response = await Client.GetAsync("http://localhost/Routing/HasEndpointMatch");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
var result = JsonConvert.DeserializeObject<bool>(body);
|
||||
|
||||
Assert.False(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -26,6 +26,9 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
|
||||
public HttpClient Client { get; }
|
||||
|
||||
[Fact]
|
||||
public abstract Task HasEndpointMatch();
|
||||
|
||||
[Theory]
|
||||
[InlineData("http://localhost/RequestScopedService/FromFilter")]
|
||||
[InlineData("http://localhost/RequestScopedService/FromView")]
|
||||
|
|
|
|||
|
|
@ -17,6 +17,21 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
{
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async override Task HasEndpointMatch()
|
||||
{
|
||||
// Arrange & Act
|
||||
var response = await Client.GetAsync("http://localhost/Routing/HasEndpointMatch");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
var result = JsonConvert.DeserializeObject<bool>(body);
|
||||
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async override Task RouteData_Routers_ConventionalRoute()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
|
||||
public HttpClient Client { get; }
|
||||
|
||||
[Fact]
|
||||
public abstract Task HasEndpointMatch();
|
||||
|
||||
[Fact]
|
||||
public abstract Task RouteData_Routers_ConventionalRoute();
|
||||
|
||||
|
|
@ -251,7 +254,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
[InlineData("Patch", "/Friends")]
|
||||
[InlineData("Options", "/Friends")]
|
||||
[InlineData("Head", "/Friends")]
|
||||
public async Task AttributeRoutedAction_RejectsRequestsWithWrongMethods_InRoutesWithoutExtraTemplateSegmentsOnTheAction(
|
||||
public virtual async Task AttributeRoutedAction_RejectsRequestsWithWrongMethods_InRoutesWithoutExtraTemplateSegmentsOnTheAction(
|
||||
string method,
|
||||
string url)
|
||||
{
|
||||
|
|
@ -318,7 +321,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AttributeRoutedAction_MultipleRouteAttributes_RouteAttributeTemplatesIgnoredForOverrideActions()
|
||||
public virtual async Task AttributeRoutedAction_MultipleRouteAttributes_RouteAttributeTemplatesIgnoredForOverrideActions()
|
||||
{
|
||||
// Arrange
|
||||
var url = "http://localhost/api/v1/Maps";
|
||||
|
|
@ -392,7 +395,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
[InlineData("http://localhost/api/v2/Maps/5", "PATCH")]
|
||||
[InlineData("http://localhost/api/v1/Maps/PartialUpdate/5", "PUT")]
|
||||
[InlineData("http://localhost/api/v2/Maps/PartialUpdate/5", "PUT")]
|
||||
public async Task AttributeRoutedAction_MultipleRouteAttributes_WithMultipleHttpAttributes_RespectsConstraints(
|
||||
public virtual async Task AttributeRoutedAction_MultipleRouteAttributes_WithMultipleHttpAttributes_RespectsConstraints(
|
||||
string url,
|
||||
string method)
|
||||
{
|
||||
|
|
@ -1209,7 +1212,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
[InlineData("/Bank/Deposit", "GET")]
|
||||
[InlineData("/Bank/Deposit/5", "DELETE")]
|
||||
[InlineData("/Bank/Withdraw/5", "GET")]
|
||||
public async Task AttributeRouting_MixedAcceptVerbsAndRoute_Unreachable(string path, string verb)
|
||||
public virtual async Task AttributeRouting_MixedAcceptVerbsAndRoute_Unreachable(string path, string verb)
|
||||
{
|
||||
// Arrange
|
||||
var request = new HttpRequestMessage(new HttpMethod(verb), "http://localhost" + path);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
// 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.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||
{
|
||||
public class VersioningGlobalRoutingTests : VersioningTestsBase<VersioningWebSite.StartupWithGlobalRouting>
|
||||
|
|
@ -9,5 +14,20 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
: base(fixture)
|
||||
{
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async override Task HasEndpointMatch()
|
||||
{
|
||||
// Arrange & Act
|
||||
var response = await Client.GetAsync("http://localhost/Routing/HasEndpointMatch");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
var result = JsonConvert.DeserializeObject<bool>(body);
|
||||
|
||||
Assert.True(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,11 @@
|
|||
// 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.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||
{
|
||||
public class VersioningTests : VersioningTestsBase<VersioningWebSite.Startup>
|
||||
|
|
@ -9,5 +14,20 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
: base(fixture)
|
||||
{
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async override Task HasEndpointMatch()
|
||||
{
|
||||
// Arrange & Act
|
||||
var response = await Client.GetAsync("http://localhost/Routing/HasEndpointMatch");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
var result = JsonConvert.DeserializeObject<bool>(body);
|
||||
|
||||
Assert.False(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -25,6 +25,9 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
|
||||
public HttpClient Client { get; }
|
||||
|
||||
[Fact]
|
||||
public abstract Task HasEndpointMatch();
|
||||
|
||||
[Theory]
|
||||
[InlineData("1")]
|
||||
[InlineData("2")]
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
|
|||
Assert.Equal(InputFormatterExceptionPolicy.AllExceptions, mvcOptions.InputFormatterExceptionPolicy);
|
||||
Assert.False(jsonOptions.AllowInputFormatterExceptionMessages);
|
||||
Assert.False(razorPagesOptions.AllowAreas);
|
||||
Assert.False(mvcOptions.EnableGlobalRouting);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -63,6 +64,32 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
|
|||
Assert.Equal(InputFormatterExceptionPolicy.MalformedInputExceptions, mvcOptions.InputFormatterExceptionPolicy);
|
||||
Assert.True(jsonOptions.AllowInputFormatterExceptionMessages);
|
||||
Assert.True(razorPagesOptions.AllowAreas);
|
||||
Assert.False(mvcOptions.EnableGlobalRouting);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CompatibilitySwitches_Version_2_2()
|
||||
{
|
||||
// Arrange
|
||||
var serviceCollection = new ServiceCollection();
|
||||
AddHostingServices(serviceCollection);
|
||||
serviceCollection.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
|
||||
|
||||
var services = serviceCollection.BuildServiceProvider();
|
||||
|
||||
// Act
|
||||
var mvcOptions = services.GetRequiredService<IOptions<MvcOptions>>().Value;
|
||||
var jsonOptions = services.GetRequiredService<IOptions<MvcJsonOptions>>().Value;
|
||||
var razorPagesOptions = services.GetRequiredService<IOptions<RazorPagesOptions>>().Value;
|
||||
|
||||
// Assert
|
||||
Assert.True(mvcOptions.AllowCombiningAuthorizeFilters);
|
||||
Assert.True(mvcOptions.AllowBindingHeaderValuesToNonStringModelTypes);
|
||||
Assert.True(mvcOptions.SuppressBindingUndefinedValueToEnumType);
|
||||
Assert.Equal(InputFormatterExceptionPolicy.MalformedInputExceptions, mvcOptions.InputFormatterExceptionPolicy);
|
||||
Assert.True(jsonOptions.AllowInputFormatterExceptionMessages);
|
||||
Assert.True(razorPagesOptions.AllowAreas);
|
||||
Assert.True(mvcOptions.EnableGlobalRouting);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -87,6 +114,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
|
|||
Assert.Equal(InputFormatterExceptionPolicy.MalformedInputExceptions, mvcOptions.InputFormatterExceptionPolicy);
|
||||
Assert.True(jsonOptions.AllowInputFormatterExceptionMessages);
|
||||
Assert.True(razorPagesOptions.AllowAreas);
|
||||
Assert.True(mvcOptions.EnableGlobalRouting);
|
||||
}
|
||||
|
||||
// This just does the minimum needed to be able to resolve these options.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
// 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.Mvc;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
|
||||
namespace BasicWebSite
|
||||
{
|
||||
public class RoutingController : Controller
|
||||
{
|
||||
public ActionResult HasEndpointMatch()
|
||||
{
|
||||
var endpointFeature = HttpContext.Features.Get<IEndpointFeature>();
|
||||
return Json(endpointFeature?.Endpoint != null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -26,6 +26,9 @@ namespace BasicWebSite
|
|||
options.Conventions.Add(new ApplicationDescription("This is a basic website."));
|
||||
// Filter that records a value in HttpContext.Items
|
||||
options.Filters.Add(new TraceResourceFilter());
|
||||
|
||||
// Remove when all URL generation tests are passing - https://github.com/aspnet/Routing/issues/590
|
||||
options.EnableGlobalRouting = false;
|
||||
})
|
||||
.SetCompatibilityVersion(CompatibilityVersion.Latest)
|
||||
.AddXmlDataContractSerializerFormatters();
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ namespace BasicWebSite
|
|||
services.AddRouting();
|
||||
|
||||
services.AddMvc()
|
||||
.SetCompatibilityVersion(CompatibilityVersion.Latest)
|
||||
.SetCompatibilityVersion(CompatibilityVersion.Latest) // this compat version enables global routing
|
||||
.AddXmlDataContractSerializerFormatters();
|
||||
|
||||
services.ConfigureBaseWebSiteAuthPolicies();
|
||||
|
|
@ -31,9 +31,9 @@ namespace BasicWebSite
|
|||
|
||||
app.UseGlobalRouting();
|
||||
|
||||
app.UseMvcWithEndpoint(routes =>
|
||||
app.UseMvc(routes =>
|
||||
{
|
||||
routes.MapEndpoint(
|
||||
routes.MapRoute(
|
||||
"ActionAsMethod",
|
||||
"{controller}/{action}",
|
||||
defaults: new { controller = "Home", action = "Index" });
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
// 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.Mvc;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
|
||||
namespace RoutingWebSite
|
||||
{
|
||||
public class RoutingController : Controller
|
||||
{
|
||||
public ActionResult HasEndpointMatch()
|
||||
{
|
||||
var endpointFeature = HttpContext.Features.Get<IEndpointFeature>();
|
||||
return Json(endpointFeature?.Endpoint != null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -12,9 +12,8 @@ namespace RoutingWebSite
|
|||
// Set up application services
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddRouting();
|
||||
|
||||
services.AddMvc();
|
||||
services.AddMvc()
|
||||
.AddMvcOptions(options => options.EnableGlobalRouting = true);
|
||||
|
||||
services.AddScoped<TestResponseGenerator>();
|
||||
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
|
||||
|
|
@ -22,23 +21,21 @@ namespace RoutingWebSite
|
|||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
app.UseGlobalRouting();
|
||||
|
||||
app.UseMvcWithEndpoint(routes =>
|
||||
app.UseMvc(routes =>
|
||||
{
|
||||
routes.MapAreaEndpoint(
|
||||
routes.MapAreaRoute(
|
||||
"flightRoute",
|
||||
"adminRoute",
|
||||
"{area:exists}/{controller}/{action}",
|
||||
new { controller = "Home", action = "Index" },
|
||||
new { area = "Travel" });
|
||||
|
||||
routes.MapEndpoint(
|
||||
routes.MapRoute(
|
||||
"ActionAsMethod",
|
||||
"{controller}/{action}",
|
||||
defaults: new { controller = "Home", action = "Index" });
|
||||
|
||||
routes.MapEndpoint(
|
||||
routes.MapRoute(
|
||||
"RouteWithOptionalSegment",
|
||||
"{controller}/{action}/{path?}");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
// 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.Mvc;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
|
||||
namespace VersioningWebSite
|
||||
{
|
||||
public class RoutingController : Controller
|
||||
{
|
||||
public ActionResult HasEndpointMatch()
|
||||
{
|
||||
var endpointFeature = HttpContext.Features.Get<IEndpointFeature>();
|
||||
return Json(endpointFeature?.Endpoint != null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,10 +13,9 @@ namespace VersioningWebSite
|
|||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddRouting();
|
||||
|
||||
// Add MVC services to the services container
|
||||
services.AddMvc();
|
||||
services.AddMvc()
|
||||
.AddMvcOptions(options => options.EnableGlobalRouting = true);
|
||||
|
||||
services.AddScoped<TestResponseGenerator>();
|
||||
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
|
||||
|
|
@ -24,14 +23,7 @@ namespace VersioningWebSite
|
|||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
app.UseGlobalRouting();
|
||||
|
||||
app.UseMvcWithEndpoint(endpoints =>
|
||||
{
|
||||
endpoints.MapEndpoint(
|
||||
name: "default",
|
||||
template: "{controller=Home}/{action=Index}/{id?}");
|
||||
});
|
||||
app.UseMvcWithDefaultRoute();
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue