Add EndpointBuilder (#701)
This commit is contained in:
parent
14a3a98f48
commit
95267a32e2
|
|
@ -2,7 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Internal;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Routing.Matching;
|
||||
using Microsoft.AspNetCore.Routing.Patterns;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Routing.Matching;
|
||||
using Microsoft.AspNetCore.Routing.Patterns;
|
||||
|
||||
namespace Microsoft.AspNetCore.Builder
|
||||
{
|
||||
public static class EndpointDataSourceBuilderExtensions
|
||||
{
|
||||
public static EndpointBuilder MapHello(this EndpointDataSourceBuilder builder, string template, string greeter)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
var pipeline = builder.CreateApplicationBuilder()
|
||||
.UseHello(greeter)
|
||||
.Build();
|
||||
|
||||
return builder.MapEndpoint(
|
||||
(next) => pipeline,
|
||||
template,
|
||||
"Hello");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.Extensions.Options;
|
||||
using RoutingSample.Web.HelloExtension;
|
||||
|
||||
namespace Microsoft.AspNetCore.Builder
|
||||
{
|
||||
public static class HelloAppBuilderExtensions
|
||||
{
|
||||
public static IApplicationBuilder UseHello(this IApplicationBuilder app, string greeter)
|
||||
{
|
||||
if (app == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(app));
|
||||
}
|
||||
|
||||
return app.UseMiddleware<HelloMiddleware>(Options.Create(new HelloOptions
|
||||
{
|
||||
Greeter = greeter
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace RoutingSample.Web.HelloExtension
|
||||
{
|
||||
public class HelloMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly HelloOptions _helloOptions;
|
||||
private readonly byte[] _helloPayload;
|
||||
|
||||
public HelloMiddleware(RequestDelegate next, IOptions<HelloOptions> helloOptions)
|
||||
{
|
||||
_next = next;
|
||||
_helloOptions = helloOptions.Value;
|
||||
|
||||
var payload = new List<byte>();
|
||||
payload.AddRange(Encoding.UTF8.GetBytes("Hello"));
|
||||
if (!string.IsNullOrEmpty(_helloOptions.Greeter))
|
||||
{
|
||||
payload.Add((byte)' ');
|
||||
payload.AddRange(Encoding.UTF8.GetBytes(_helloOptions.Greeter));
|
||||
}
|
||||
_helloPayload = payload.ToArray();
|
||||
}
|
||||
|
||||
public Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
var response = context.Response;
|
||||
var payloadLength = _helloPayload.Length;
|
||||
response.StatusCode = 200;
|
||||
response.ContentType = "text/plain";
|
||||
response.ContentLength = payloadLength;
|
||||
return response.Body.WriteAsync(_helloPayload, 0, payloadLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
// 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.
|
||||
|
||||
namespace RoutingSample.Web.HelloExtension
|
||||
{
|
||||
public class HelloOptions
|
||||
{
|
||||
public string Greeter { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -3,20 +3,16 @@
|
|||
|
||||
using System;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Internal;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Routing.Matching;
|
||||
using Microsoft.AspNetCore.Routing.Patterns;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace RoutingSample.Web
|
||||
{
|
||||
public class UseEndpointRoutingStartup
|
||||
{
|
||||
private static readonly byte[] _homePayload = Encoding.UTF8.GetBytes("Endpoint Routing sample endpoints:" + Environment.NewLine + "/plaintext");
|
||||
private static readonly byte[] _helloWorldPayload = Encoding.UTF8.GetBytes("Hello, World!");
|
||||
private static readonly byte[] _plainTextPayload = Encoding.UTF8.GetBytes("Plain text!");
|
||||
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
|
|
@ -26,65 +22,59 @@ namespace RoutingSample.Web
|
|||
{
|
||||
options.ConstraintMap.Add("endsWith", typeof(EndsWithStringMatchProcessor));
|
||||
});
|
||||
|
||||
var endpointDataSource = new DefaultEndpointDataSource(new[]
|
||||
{
|
||||
new MatcherEndpoint((next) => (httpContext) =>
|
||||
{
|
||||
var response = httpContext.Response;
|
||||
var payloadLength = _homePayload.Length;
|
||||
response.StatusCode = 200;
|
||||
response.ContentType = "text/plain";
|
||||
response.ContentLength = payloadLength;
|
||||
return response.Body.WriteAsync(_homePayload, 0, payloadLength);
|
||||
},
|
||||
RoutePatternFactory.Parse("/"),
|
||||
0,
|
||||
EndpointMetadataCollection.Empty,
|
||||
"Home"),
|
||||
new MatcherEndpoint((next) => (httpContext) =>
|
||||
{
|
||||
var response = httpContext.Response;
|
||||
var payloadLength = _helloWorldPayload.Length;
|
||||
response.StatusCode = 200;
|
||||
response.ContentType = "text/plain";
|
||||
response.ContentLength = payloadLength;
|
||||
return response.Body.WriteAsync(_helloWorldPayload, 0, payloadLength);
|
||||
},
|
||||
RoutePatternFactory.Parse("/plaintext"),
|
||||
0,
|
||||
EndpointMetadataCollection.Empty,
|
||||
"Plaintext"),
|
||||
new MatcherEndpoint((next) => (httpContext) =>
|
||||
{
|
||||
var response = httpContext.Response;
|
||||
response.StatusCode = 200;
|
||||
response.ContentType = "text/plain";
|
||||
return response.WriteAsync("WithConstraints");
|
||||
},
|
||||
RoutePatternFactory.Parse("/withconstraints/{id:endsWith(_001)}"),
|
||||
0,
|
||||
EndpointMetadataCollection.Empty,
|
||||
"withconstraints"),
|
||||
new MatcherEndpoint((next) => (httpContext) =>
|
||||
{
|
||||
var response = httpContext.Response;
|
||||
response.StatusCode = 200;
|
||||
response.ContentType = "text/plain";
|
||||
return response.WriteAsync("withoptionalconstraints");
|
||||
},
|
||||
RoutePatternFactory.Parse("/withoptionalconstraints/{id:endsWith(_001)?}"),
|
||||
0,
|
||||
EndpointMetadataCollection.Empty,
|
||||
"withoptionalconstraints"),
|
||||
});
|
||||
|
||||
services.TryAddEnumerable(ServiceDescriptor.Singleton<EndpointDataSource>(endpointDataSource));
|
||||
}
|
||||
|
||||
public void Configure(Microsoft.AspNetCore.Builder.IApplicationBuilder app)
|
||||
{
|
||||
app.UseEndpointRouting();
|
||||
app.UseEndpointRouting(builder =>
|
||||
{
|
||||
builder.MapHello("/helloworld", "World");
|
||||
|
||||
builder.MapEndpoint(
|
||||
(next) => (httpContext) =>
|
||||
{
|
||||
var response = httpContext.Response;
|
||||
var payloadLength = _homePayload.Length;
|
||||
response.StatusCode = 200;
|
||||
response.ContentType = "text/plain";
|
||||
response.ContentLength = payloadLength;
|
||||
return response.Body.WriteAsync(_homePayload, 0, payloadLength);
|
||||
},
|
||||
"/",
|
||||
"Home");
|
||||
builder.MapEndpoint(
|
||||
(next) => (httpContext) =>
|
||||
{
|
||||
var response = httpContext.Response;
|
||||
var payloadLength = _plainTextPayload.Length;
|
||||
response.StatusCode = 200;
|
||||
response.ContentType = "text/plain";
|
||||
response.ContentLength = payloadLength;
|
||||
return response.Body.WriteAsync(_plainTextPayload, 0, payloadLength);
|
||||
},
|
||||
"/plaintext",
|
||||
"Plaintext");
|
||||
builder.MapEndpoint(
|
||||
(next) => (httpContext) =>
|
||||
{
|
||||
var response = httpContext.Response;
|
||||
response.StatusCode = 200;
|
||||
response.ContentType = "text/plain";
|
||||
return response.WriteAsync("WithConstraints");
|
||||
},
|
||||
"/withconstraints/{id:endsWith(_001)}",
|
||||
"withconstraints");
|
||||
builder.MapEndpoint(
|
||||
(next) => (httpContext) =>
|
||||
{
|
||||
var response = httpContext.Response;
|
||||
response.StatusCode = 200;
|
||||
response.ContentType = "text/plain";
|
||||
return response.WriteAsync("withoptionalconstraints");
|
||||
},
|
||||
"/withoptionalconstraints/{id:endsWith(_001)?}",
|
||||
"withoptionalconstraints");
|
||||
});
|
||||
|
||||
// Imagine some more stuff here...
|
||||
|
||||
|
|
|
|||
|
|
@ -7,16 +7,28 @@ using Microsoft.AspNetCore.Routing;
|
|||
using Microsoft.AspNetCore.Routing.Internal;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNetCore.Internal
|
||||
namespace Microsoft.AspNetCore.Builder
|
||||
{
|
||||
public static class EndpointRoutingApplicationBuilderExtensions
|
||||
{
|
||||
private const string EndpointRoutingRegisteredKey = "__EndpointRoutingMiddlewareRegistered";
|
||||
|
||||
public static IApplicationBuilder UseEndpointRouting(this IApplicationBuilder builder)
|
||||
{
|
||||
return builder.UseEndpointRouting(null);
|
||||
}
|
||||
|
||||
public static IApplicationBuilder UseEndpointRouting(this IApplicationBuilder builder, Action<EndpointDataSourceBuilder> configure)
|
||||
{
|
||||
VerifyRoutingIsRegistered(builder);
|
||||
|
||||
if (configure != null)
|
||||
{
|
||||
var dataSourceBuilder = (DefaultEndpointDataSourceBuilder)builder.ApplicationServices.GetRequiredService<EndpointDataSourceBuilder>();
|
||||
dataSourceBuilder.ApplicationBuilder = builder;
|
||||
configure(dataSourceBuilder);
|
||||
}
|
||||
|
||||
builder.Properties[EndpointRoutingRegisteredKey] = true;
|
||||
|
||||
return builder.UseMiddleware<EndpointRoutingMiddleware>();
|
||||
|
|
@ -50,4 +62,4 @@ namespace Microsoft.AspNetCore.Internal
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Routing.Matching;
|
||||
using Microsoft.AspNetCore.Routing.Patterns;
|
||||
|
||||
namespace Microsoft.AspNetCore.Builder
|
||||
{
|
||||
public static class MapEndpointEndpointDataSourceBuilderExtensions
|
||||
{
|
||||
public static MatcherEndpointBuilder MapEndpoint(
|
||||
this EndpointDataSourceBuilder builder,
|
||||
Func<RequestDelegate, RequestDelegate> invoker,
|
||||
string pattern,
|
||||
string displayName)
|
||||
{
|
||||
return MapEndpoint(builder, invoker, pattern, displayName, metadata: null);
|
||||
}
|
||||
|
||||
public static MatcherEndpointBuilder MapEndpoint(
|
||||
this EndpointDataSourceBuilder builder,
|
||||
Func<RequestDelegate, RequestDelegate> invoker,
|
||||
RoutePattern pattern,
|
||||
string displayName)
|
||||
{
|
||||
return MapEndpoint(builder, invoker, pattern, displayName, metadata: null);
|
||||
}
|
||||
|
||||
public static MatcherEndpointBuilder MapEndpoint(
|
||||
this EndpointDataSourceBuilder builder,
|
||||
Func<RequestDelegate, RequestDelegate> invoker,
|
||||
string pattern,
|
||||
string displayName,
|
||||
IList<object> metadata)
|
||||
{
|
||||
return MapEndpoint(builder, invoker, RoutePatternFactory.Parse(pattern), displayName, metadata);
|
||||
}
|
||||
|
||||
public static MatcherEndpointBuilder MapEndpoint(
|
||||
this EndpointDataSourceBuilder builder,
|
||||
Func<RequestDelegate, RequestDelegate> invoker,
|
||||
RoutePattern pattern,
|
||||
string displayName,
|
||||
IList<object> metadata)
|
||||
{
|
||||
const int defaultOrder = 0;
|
||||
|
||||
var endpointBuilder = new MatcherEndpointBuilder(
|
||||
invoker,
|
||||
pattern,
|
||||
defaultOrder);
|
||||
endpointBuilder.DisplayName = displayName;
|
||||
if (metadata != null)
|
||||
{
|
||||
foreach (var item in metadata)
|
||||
{
|
||||
endpointBuilder.Metadata.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
builder.Endpoints.Add(endpointBuilder);
|
||||
return endpointBuilder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing
|
||||
{
|
||||
internal class BuilderEndpointDataSource : EndpointDataSource
|
||||
{
|
||||
private readonly EndpointDataSourceBuilder _builder;
|
||||
|
||||
public BuilderEndpointDataSource(EndpointDataSourceBuilder builder)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
_builder = builder;
|
||||
}
|
||||
|
||||
public override IChangeToken GetChangeToken()
|
||||
{
|
||||
return NullChangeToken.Singleton;
|
||||
}
|
||||
|
||||
public override IReadOnlyList<Endpoint> Endpoints => _builder.Endpoints.Select(b => b.Build()).ToArray();
|
||||
}
|
||||
}
|
||||
|
|
@ -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 System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing
|
||||
{
|
||||
internal class DefaultEndpointDataSourceBuilder : EndpointDataSourceBuilder
|
||||
{
|
||||
public IApplicationBuilder ApplicationBuilder { get; set; }
|
||||
|
||||
public override ICollection<EndpointBuilder> Endpoints { get; } = new List<EndpointBuilder>();
|
||||
|
||||
public override IApplicationBuilder CreateApplicationBuilder() => ApplicationBuilder.New();
|
||||
}
|
||||
}
|
||||
|
|
@ -59,6 +59,12 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
return new CompositeEndpointDataSource(options.Value.DataSources);
|
||||
});
|
||||
|
||||
//
|
||||
// Endpoint Infrastructure
|
||||
//
|
||||
services.TryAddSingleton<EndpointDataSource, BuilderEndpointDataSource>();
|
||||
services.TryAddSingleton<EndpointDataSourceBuilder, DefaultEndpointDataSourceBuilder>();
|
||||
|
||||
//
|
||||
// Default matcher implementation
|
||||
//
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing
|
||||
{
|
||||
public abstract class EndpointBuilder
|
||||
{
|
||||
public string DisplayName { get; set; }
|
||||
|
||||
public IList<object> Metadata { get; } = new List<object>();
|
||||
|
||||
public abstract Endpoint Build();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
// 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 Microsoft.AspNetCore.Builder;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing
|
||||
{
|
||||
public abstract class EndpointDataSourceBuilder
|
||||
{
|
||||
public abstract ICollection<EndpointBuilder> Endpoints { get; }
|
||||
|
||||
public abstract IApplicationBuilder CreateApplicationBuilder();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing.Patterns;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing.Matching
|
||||
{
|
||||
public sealed class MatcherEndpointBuilder : EndpointBuilder
|
||||
{
|
||||
public Func<RequestDelegate, RequestDelegate> Invoker { get; set; }
|
||||
|
||||
public RoutePattern RoutePattern { get; set; }
|
||||
|
||||
public int Order { get; set; }
|
||||
|
||||
public MatcherEndpointBuilder(
|
||||
Func<RequestDelegate, RequestDelegate> invoker,
|
||||
RoutePattern routePattern,
|
||||
int order)
|
||||
{
|
||||
Invoker = invoker;
|
||||
RoutePattern = routePattern;
|
||||
Order = order;
|
||||
}
|
||||
|
||||
public override Endpoint Build()
|
||||
{
|
||||
var matcherEndpoint = new MatcherEndpoint(
|
||||
Invoker,
|
||||
RoutePattern,
|
||||
Order,
|
||||
new EndpointMetadataCollection(Metadata),
|
||||
DisplayName);
|
||||
|
||||
return matcherEndpoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.Routing.FunctionalTests
|
|||
{
|
||||
// Arrange
|
||||
var expectedContentType = "text/plain";
|
||||
var expectedContent = "Hello, World!";
|
||||
var expectedContent = "Plain text!";
|
||||
|
||||
// Act
|
||||
var response = await _client.GetAsync("/plaintext");
|
||||
|
|
@ -62,6 +62,25 @@ namespace Microsoft.AspNetCore.Routing.FunctionalTests
|
|||
Assert.Equal(expectedContent, actualContent);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MatchesHelloMiddleware_AndReturnsPlaintext()
|
||||
{
|
||||
// Arrange
|
||||
var expectedContentType = "text/plain";
|
||||
var expectedContent = "Hello World";
|
||||
|
||||
// Act
|
||||
var response = await _client.GetAsync("/helloworld");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.NotNull(response.Content.Headers.ContentType);
|
||||
Assert.Equal(expectedContentType, response.Content.Headers.ContentType.MediaType);
|
||||
var actualContent = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal(expectedContent, actualContent);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MatchesEndpoint_WithSuccessfulConstraintMatch()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ using System;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder.Internal;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Internal;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Moq;
|
||||
|
|
@ -13,7 +12,7 @@ using Xunit;
|
|||
|
||||
namespace Microsoft.AspNetCore.Builder
|
||||
{
|
||||
public class EndpointRoutingBuilderExtensionsTest
|
||||
public class EndpointRoutingApplicationBuilderExtensionsTest
|
||||
{
|
||||
[Fact]
|
||||
public void UseEndpointRouting_ServicesNotRegistered_Throws()
|
||||
|
|
@ -109,6 +108,26 @@ namespace Microsoft.AspNetCore.Builder
|
|||
Assert.NotNull(httpContext.Features.Get<IEndpointFeature>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UseEndpointRouting_CallWithBuilder_SetsEndpointBuilder()
|
||||
{
|
||||
// Arrange
|
||||
var services = CreateServices();
|
||||
|
||||
var app = new ApplicationBuilder(services);
|
||||
|
||||
// Act
|
||||
app.UseEndpointRouting(builder =>
|
||||
{
|
||||
builder.MapEndpoint(d => null, "/", "Test endpoint");
|
||||
});
|
||||
|
||||
// Assert
|
||||
var dataSourceBuilder = (DefaultEndpointDataSourceBuilder)services.GetRequiredService<EndpointDataSourceBuilder>();
|
||||
var endpointBuilder = Assert.Single(dataSourceBuilder.Endpoints);
|
||||
Assert.Equal("Test endpoint", endpointBuilder.DisplayName);
|
||||
}
|
||||
|
||||
private IServiceProvider CreateServices()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Routing.Matching;
|
||||
using Microsoft.AspNetCore.Routing.Patterns;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Builder
|
||||
{
|
||||
public class MapEndpointEndpointDataSourceBuilderExtensionsTest
|
||||
{
|
||||
[Fact]
|
||||
public void MapEndpoint_StringPattern_BuildsEndpoint()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new DefaultEndpointDataSourceBuilder();
|
||||
Func<RequestDelegate, RequestDelegate> invoker = (d) => null;
|
||||
|
||||
// Act
|
||||
var endpointBuilder = builder.MapEndpoint(invoker, "/", "Display name!");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(endpointBuilder, Assert.Single(builder.Endpoints));
|
||||
Assert.Equal(invoker, endpointBuilder.Invoker);
|
||||
Assert.Equal("Display name!", endpointBuilder.DisplayName);
|
||||
Assert.Equal("/", endpointBuilder.RoutePattern.RawText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MapEndpoint_TypedPattern_BuildsEndpoint()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new DefaultEndpointDataSourceBuilder();
|
||||
Func<RequestDelegate, RequestDelegate> invoker = (d) => null;
|
||||
|
||||
// Act
|
||||
var endpointBuilder = builder.MapEndpoint(invoker, RoutePatternFactory.Parse("/"), "Display name!");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(endpointBuilder, Assert.Single(builder.Endpoints));
|
||||
Assert.Equal(invoker, endpointBuilder.Invoker);
|
||||
Assert.Equal("Display name!", endpointBuilder.DisplayName);
|
||||
Assert.Equal("/", endpointBuilder.RoutePattern.RawText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MapEndpoint_StringPatternAndMetadata_BuildsEndpoint()
|
||||
{
|
||||
// Arrange
|
||||
var metadata = new object();
|
||||
var builder = new DefaultEndpointDataSourceBuilder();
|
||||
Func<RequestDelegate, RequestDelegate> invoker = (d) => null;
|
||||
|
||||
// Act
|
||||
var endpointBuilder = builder.MapEndpoint(invoker, "/", "Display name!", new[] { metadata });
|
||||
|
||||
// Assert
|
||||
Assert.Equal(endpointBuilder, Assert.Single(builder.Endpoints));
|
||||
Assert.Equal(invoker, endpointBuilder.Invoker);
|
||||
Assert.Equal("Display name!", endpointBuilder.DisplayName);
|
||||
Assert.Equal("/", endpointBuilder.RoutePattern.RawText);
|
||||
Assert.Equal(metadata, Assert.Single(endpointBuilder.Metadata));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MapEndpoint_TypedPatternAndMetadata_BuildsEndpoint()
|
||||
{
|
||||
// Arrange
|
||||
var metadata = new object();
|
||||
var builder = new DefaultEndpointDataSourceBuilder();
|
||||
Func<RequestDelegate, RequestDelegate> invoker = (d) => null;
|
||||
|
||||
// Act
|
||||
var endpointBuilder = builder.MapEndpoint(invoker, RoutePatternFactory.Parse("/"), "Display name!", new[] { metadata });
|
||||
|
||||
// Assert
|
||||
Assert.Equal(endpointBuilder, Assert.Single(builder.Endpoints));
|
||||
Assert.Equal(invoker, endpointBuilder.Invoker);
|
||||
Assert.Equal("Display name!", endpointBuilder.DisplayName);
|
||||
Assert.Equal("/", endpointBuilder.RoutePattern.RawText);
|
||||
Assert.Equal(metadata, Assert.Single(endpointBuilder.Metadata));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing.Patterns;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing.Matching
|
||||
{
|
||||
public class MatcherEndpointBuilderTest
|
||||
{
|
||||
[Fact]
|
||||
public void Build_AllValuesSet_EndpointCreated()
|
||||
{
|
||||
const int defaultOrder = 0;
|
||||
object metadata = new object();
|
||||
Func<RequestDelegate, RequestDelegate> invoker = (d) => null;
|
||||
|
||||
var builder = new MatcherEndpointBuilder(invoker, RoutePatternFactory.Parse("/"), defaultOrder)
|
||||
{
|
||||
DisplayName = "Display name!",
|
||||
Metadata = { metadata }
|
||||
};
|
||||
|
||||
var endpoint = Assert.IsType<MatcherEndpoint>(builder.Build());
|
||||
Assert.Equal("Display name!", endpoint.DisplayName);
|
||||
Assert.Equal(defaultOrder, endpoint.Order);
|
||||
Assert.Equal(invoker, endpoint.Invoker);
|
||||
Assert.Equal("/", endpoint.RoutePattern.RawText);
|
||||
Assert.Equal(metadata, Assert.Single(endpoint.Metadata));
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue