Check dispatcher services registered (#610)

This commit is contained in:
James Newton-King 2018-07-14 18:20:42 +12:00 committed by GitHub
parent 5e1f99faaf
commit 73e4d55d7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 143 additions and 2 deletions

View File

@ -1,7 +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.
using System;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Routing.Internal;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Builder
{
@ -9,12 +12,29 @@ namespace Microsoft.AspNetCore.Builder
{
public static IApplicationBuilder UseDispatcher(this IApplicationBuilder builder)
{
VerifyDispatcherIsRegistered(builder);
return builder.UseMiddleware<DispatcherMiddleware>();
}
public static IApplicationBuilder UseEndpoint(this IApplicationBuilder builder)
{
VerifyDispatcherIsRegistered(builder);
return builder.UseMiddleware<EndpointMiddleware>();
}
private static void VerifyDispatcherIsRegistered(IApplicationBuilder app)
{
// Verify if AddDispatcher was done before calling UseDispatcher/UseEndpoint
// We use the DispatcherMarkerService to make sure if all the services were added.
if (app.ApplicationServices.GetService(typeof(DispatcherMarkerService)) == null)
{
throw new InvalidOperationException(Resources.FormatUnableToFindServices(
nameof(IServiceCollection),
nameof(DispatcherServiceCollectionExtensions.AddDispatcher),
"ConfigureServices(...)"));
}
}
}
}

View File

@ -6,6 +6,7 @@ using System.Reflection;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Routing.EndpointConstraints;
using Microsoft.AspNetCore.Routing.EndpointFinders;
using Microsoft.AspNetCore.Routing.Internal;
using Microsoft.AspNetCore.Routing.Matchers;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
@ -34,6 +35,7 @@ namespace Microsoft.Extensions.DependencyInjection
//
// Default matcher implementation
//
services.TryAddSingleton<MatchProcessorFactory, DefaultMatchProcessorFactory>();
services.TryAddSingleton<MatcherFactory, TreeMatcherFactory>();
// Link generation related services
@ -50,6 +52,8 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAddEnumerable(
ServiceDescriptor.Transient<IEndpointConstraintProvider, DefaultEndpointConstraintProvider>());
services.TryAddSingleton(typeof(DispatcherMarkerService));
return services;
}

View File

@ -30,7 +30,6 @@ namespace Microsoft.Extensions.DependencyInjection
throw new ArgumentNullException(nameof(services));
}
services.TryAddSingleton<MatchProcessorFactory, DefaultMatchProcessorFactory>();
services.TryAddTransient<IInlineConstraintResolver, DefaultInlineConstraintResolver>();
services.TryAddSingleton<ObjectPool<UriBuildingContext>>(s =>
{

View File

@ -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 Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Routing.Internal
{
/// <summary>
/// A marker class used to determine if all the dispatcher services were added
/// to the <see cref="IServiceCollection"/> before dispatcher is configured.
/// </summary>
internal class DispatcherMarkerService
{
}
}

View File

@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Routing.Internal
/// A marker class used to determine if all the routing services were added
/// to the <see cref="IServiceCollection"/> before routing is configured.
/// </summary>
public class RoutingMarkerService
internal class RoutingMarkerService
{
}
}

View File

@ -0,0 +1,103 @@
// 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.Threading.Tasks;
using Microsoft.AspNetCore.Builder.Internal;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Builder
{
public class DispatcherApplicationBuilderExtensions
{
[Fact]
public void UseDispatcher_ServicesNotRegistered_Throws()
{
// Arrange
var app = new ApplicationBuilder(Mock.Of<IServiceProvider>());
// Act
var ex = Assert.Throws<InvalidOperationException>(() => app.UseDispatcher());
// Assert
Assert.Equal(
"Unable to find the required services. " +
"Please add all the required services by calling 'IServiceCollection.AddDispatcher' " +
"inside the call to 'ConfigureServices(...)' in the application startup code.",
ex.Message);
}
[Fact]
public void UseEndpoint_ServicesNotRegistered_Throws()
{
// Arrange
var app = new ApplicationBuilder(Mock.Of<IServiceProvider>());
// Act
var ex = Assert.Throws<InvalidOperationException>(() => app.UseEndpoint());
// Assert
Assert.Equal(
"Unable to find the required services. " +
"Please add all the required services by calling 'IServiceCollection.AddDispatcher' " +
"inside the call to 'ConfigureServices(...)' in the application startup code.",
ex.Message);
}
[Fact]
public async Task UseDispatcher_ServicesRegistered_SetsFeature()
{
// Arrange
var services = CreateServices();
var app = new ApplicationBuilder(services);
app.UseDispatcher();
var appFunc = app.Build();
var httpContext = new DefaultHttpContext();
// Act
await appFunc(httpContext);
// Assert
Assert.NotNull(httpContext.Features.Get<IEndpointFeature>());
}
[Fact]
public async Task UseEndpoint_ServicesRegistered_SetsFeature()
{
// Arrange
var services = CreateServices();
var app = new ApplicationBuilder(services);
app.UseDispatcher();
app.UseEndpoint();
var appFunc = app.Build();
var httpContext = new DefaultHttpContext();
// Act
await appFunc(httpContext);
// Assert
Assert.NotNull(httpContext.Features.Get<IEndpointFeature>());
}
private IServiceProvider CreateServices()
{
var services = new ServiceCollection();
services.AddLogging();
services.AddOptions();
services.AddDispatcher();
return services.BuildServiceProvider();
}
}
}