parent
f49cbd1b25
commit
2f8951e244
|
|
@ -7,11 +7,9 @@ using Microsoft.AspNetCore.Builder;
|
|||
using Microsoft.AspNetCore.Dispatcher;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Routing.Dispatcher;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace DispatcherSample
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,9 +4,8 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Dispatcher;
|
||||
|
||||
namespace DispatcherSample
|
||||
namespace Microsoft.AspNetCore.Dispatcher
|
||||
{
|
||||
public class HttpMethodEndpointSelector : EndpointSelector
|
||||
{
|
||||
|
|
@ -19,19 +18,19 @@ namespace DispatcherSample
|
|||
|
||||
var snapshot = context.CreateSnapshot();
|
||||
|
||||
var fallback = new List<Endpoint>();
|
||||
var fallbackEndpoints = new List<Endpoint>();
|
||||
for (var i = context.Endpoints.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var endpoint = context.Endpoints[i] as ITemplateEndpoint;
|
||||
if (endpoint == null || endpoint.HttpMethod == null)
|
||||
{
|
||||
// No metadata.
|
||||
fallback.Add(context.Endpoints[i]);
|
||||
fallbackEndpoints.Add(context.Endpoints[i]);
|
||||
context.Endpoints.RemoveAt(i);
|
||||
}
|
||||
else if (string.Equals(endpoint.HttpMethod, context.HttpContext.Request.Method, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// This one matches.
|
||||
// The request method matches the endpoint's HTTP method.
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -50,9 +49,9 @@ namespace DispatcherSample
|
|||
context.RestoreSnapshot(snapshot);
|
||||
context.Endpoints.Clear();
|
||||
|
||||
for (var i = 0; i < fallback.Count; i++)
|
||||
for (var i = 0; i < fallbackEndpoints.Count; i++)
|
||||
{
|
||||
context.Endpoints.Add(fallback[i]);
|
||||
context.Endpoints.Add(fallbackEndpoints[i]);
|
||||
}
|
||||
|
||||
await context.InvokeNextAsync();
|
||||
|
|
@ -167,7 +167,7 @@ namespace Microsoft.AspNetCore.Routing.Dispatcher
|
|||
trees.Add(new UrlMatchingTree(trees.Count));
|
||||
}
|
||||
|
||||
var tree = trees[i];
|
||||
var tree = trees[entry.Order];
|
||||
|
||||
TreeRouteBuilder.AddEntryToTree(tree, entry);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,15 +62,31 @@ namespace Microsoft.AspNetCore.Dispatcher.FunctionalTest
|
|||
{
|
||||
Endpoints =
|
||||
{
|
||||
new TemplateEndpoint("api/products", Products_Get),
|
||||
new TemplateEndpoint("api/products", Products_Fallback),
|
||||
new TemplateEndpoint("api/products", new { controller = "Products", action = "Get", }, "GET", Products_Get),
|
||||
new TemplateEndpoint("api/products/{id}", new { controller = "Products", action = "Get", }, "GET", Products_GetWithId),
|
||||
new TemplateEndpoint("api/products", new { controller = "Products", action = "Post", }, "POST", Products_Post),
|
||||
new TemplateEndpoint("api/products/{id}", new { controller = "Products", action = "Put", }, "PUT", Products_Put),
|
||||
},
|
||||
});
|
||||
|
||||
Selectors =
|
||||
{
|
||||
new HttpMethodEndpointSelector(),
|
||||
}
|
||||
});
|
||||
options.HandlerFactories.Add(endpoint => (endpoint as TemplateEndpoint)?.HandlerFactory);
|
||||
}
|
||||
|
||||
private Task Products_Fallback(HttpContext httpContext) => httpContext.Response.WriteAsync("Hello, Products_Fallback");
|
||||
|
||||
private Task Products_Get(HttpContext httpContext) => httpContext.Response.WriteAsync("Hello, Products_Get");
|
||||
|
||||
private Task Products_GetWithId(HttpContext httpContext) => httpContext.Response.WriteAsync("Hello, Products_GetWithId");
|
||||
|
||||
private Task Products_Post(HttpContext httpContext) => httpContext.Response.WriteAsync("Hello, Products_Post");
|
||||
|
||||
private Task Products_Put(HttpContext httpContext) => httpContext.Response.WriteAsync("Hello, Products_Put");
|
||||
|
||||
private class CorsPolicyMetadata
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
|
|
|||
|
|
@ -30,5 +30,73 @@ namespace Microsoft.AspNetCore.Dispatcher.FunctionalTest
|
|||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("Hello, Products_Get", await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ApiApp_RoutesTo_EndpointWithMatchingHttpMethod()
|
||||
{
|
||||
// Arrange
|
||||
var request = new HttpRequestMessage(HttpMethod.Post, "/api/products");
|
||||
|
||||
// Act
|
||||
var response = await Client.SendAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("Hello, Products_Post", await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ApiApp_RoutesTo_EndpointWithMatchingHttpMethod_AndMatchingRoute()
|
||||
{
|
||||
// Arrange
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, "/api/products/3");
|
||||
|
||||
// Act
|
||||
var response = await Client.SendAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("Hello, Products_GetWithId", await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ApiApp_RoutesTo_EndpointWithMatchingHttpMethod_DoesNotMatchExpectedRoute()
|
||||
{
|
||||
// Arrange
|
||||
var request = new HttpRequestMessage(HttpMethod.Put, "/api/services/2");
|
||||
|
||||
// Act
|
||||
var response = await Client.SendAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ApiApp_NoEndpointWithMatchingHttpMethod_FallbackEndpointSelected()
|
||||
{
|
||||
// Arrange
|
||||
var request = new HttpRequestMessage(HttpMethod.Delete, "/api/products");
|
||||
|
||||
// Act
|
||||
var response = await Client.SendAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("Hello, Products_Fallback", await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ApiApp_NoEndpointWithMatchingHttpMethod_NoFallbackEndpointMatched()
|
||||
{
|
||||
// Arrange
|
||||
var request = new HttpRequestMessage(HttpMethod.Delete, "/api/products/4");
|
||||
|
||||
// Act
|
||||
var response = await Client.SendAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
// 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 Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Dispatcher.Abstractions.Test
|
||||
{
|
||||
public class DispatcherTest
|
||||
{
|
||||
[Fact]
|
||||
public void Test()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Dispatcher
|
||||
{
|
||||
public class HttpMethodEndpointSelectorTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("get")]
|
||||
[InlineData("Get")]
|
||||
[InlineData("GET")]
|
||||
public async Task RequestMethod_MatchesEndpointMethod_IgnoresCase(string httpMethod)
|
||||
{
|
||||
// Arrange
|
||||
var endpoints = new List<Endpoint>()
|
||||
{
|
||||
new TemplateEndpoint("{controller=Home}/{action=Index}/{id?}", new { controller = "Products", action = "Get", }, "GET", Products_Get, "Products:Get()"),
|
||||
new TemplateEndpoint("{controller=Home}/{action=Index}/{id?}", new { controller = "Products", action = "Create", }, "POST", Products_Post, "Products:Post()"),
|
||||
};
|
||||
|
||||
var (context, selector) = CreateContextAndSelector(httpMethod, endpoints);
|
||||
|
||||
// Act
|
||||
await selector.SelectAsync(context);
|
||||
var templateEndpoints = context.Endpoints.Cast<TemplateEndpoint>();
|
||||
|
||||
// Assert
|
||||
Assert.Collection(
|
||||
templateEndpoints,
|
||||
endpoint => Assert.Equal(httpMethod.ToUpperInvariant(), endpoint.HttpMethod));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RequestMethod_DoesNotMatch_AnyEndpointMethod()
|
||||
{
|
||||
// Arrange
|
||||
var endpoints = new List<Endpoint>()
|
||||
{
|
||||
new TemplateEndpoint("{controller=Home}/{action=Index}/{id?}", new { controller = "Products", action = "Get", }, "GET", Products_Get, "Products:Get()"),
|
||||
new TemplateEndpoint("{controller=Home}/{action=Index}/{id?}", new { controller = "Products", action = "Create", }, "POST", Products_Post, "Products:Post()"),
|
||||
};
|
||||
|
||||
var (context, selector) = CreateContextAndSelector("PUT", endpoints);
|
||||
|
||||
// Act
|
||||
await selector.SelectAsync(context);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(0, context.Endpoints.Count);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("PUT")]
|
||||
[InlineData(null)]
|
||||
public async Task RequestMethod_NotSpecifiedOrNotFound_ReturnsFallbackEndpointMethod(string httpMethod)
|
||||
{
|
||||
// Arrange
|
||||
var endpoints = new List<Endpoint>()
|
||||
{
|
||||
new TemplateEndpoint("{controller=Home}/{action=Index}/{id?}", new { controller = "Products", action = "Get", }, "GET", Products_Get, "Products:Get()"),
|
||||
new TemplateEndpoint("{controller=Home}/{action=Index}/{id?}", new { controller = "Products", action = "Create", }, "POST", Products_Post, "Products:Post()"),
|
||||
new TemplateEndpoint("{controller=Home}/{action=Index}/{id?}", new { controller = "Products", action = "Get", }, Products_Get),
|
||||
};
|
||||
|
||||
var (context, selector) = CreateContextAndSelector(httpMethod, endpoints);
|
||||
|
||||
// Act
|
||||
await selector.SelectAsync(context);
|
||||
var templateEndpoints = context.Endpoints.Cast<TemplateEndpoint>();
|
||||
|
||||
// Assert
|
||||
Assert.Collection(
|
||||
templateEndpoints,
|
||||
endpoint => Assert.Null(endpoint.HttpMethod));
|
||||
}
|
||||
|
||||
private (EndpointSelectorContext, EndpointSelector) CreateContextAndSelector(string httpMethod, List<Endpoint> endpoints)
|
||||
{
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.Request.Method = httpMethod;
|
||||
var selector = new HttpMethodEndpointSelector();
|
||||
var selectors = new List<EndpointSelector>()
|
||||
{
|
||||
selector
|
||||
};
|
||||
|
||||
var selectorContext = new EndpointSelectorContext(httpContext, endpoints, selectors);
|
||||
return (selectorContext, selector);
|
||||
}
|
||||
|
||||
private Task Products_Get(HttpContext httpContext) => httpContext.Response.WriteAsync("Hello, Products_Get");
|
||||
|
||||
private Task Products_Post(HttpContext httpContext) => httpContext.Response.WriteAsync("Hello, Products_Post");
|
||||
}
|
||||
}
|
||||
|
|
@ -9,4 +9,8 @@
|
|||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Dispatcher\Microsoft.AspNetCore.Dispatcher.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
Loading…
Reference in New Issue