Fixes [#276] Throw a nicer error when the routing services haven't been added to DI

This commit is contained in:
jacalvar 2016-01-13 14:33:36 -08:00
parent 672d596248
commit 9b217a4026
10 changed files with 127 additions and 0 deletions

View File

@ -3,6 +3,8 @@
using System;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.Routing.Internal;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNet.Builder
{
@ -29,6 +31,14 @@ namespace Microsoft.AspNet.Builder
throw new ArgumentNullException(nameof(router));
}
if (builder.ApplicationServices.GetService(typeof(RoutingMarkerService)) == null)
{
throw new InvalidOperationException(Resources.FormatUnableToFindServices(
nameof(IServiceCollection),
nameof(RoutingServiceCollectionExtensions.AddRouting),
"ConfigureServices(...)"));
}
return builder.UseMiddleware<RouterMiddleware>(router);
}
}

View File

@ -34,6 +34,8 @@ namespace Microsoft.Extensions.DependencyInjection
return provider.Create<UriBuildingContext>(new UriBuilderContextPooledObjectPolicy(encoder));
});
services.TryAddSingleton(typeof(RoutingMarkerService));
if (configureOptions != null)
{
services.Configure(configureOptions);

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.AspNet.Routing.Internal
{
/// <summary>
/// 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
{
}
}

View File

@ -426,6 +426,22 @@ namespace Microsoft.AspNet.Routing
return string.Format(CultureInfo.CurrentCulture, GetString("AttributeRoute_DifferentLinkGenerationEntries_SameName"), p0);
}
/// <summary>
/// Unable to find the required services. Please add all the required services by calling '{0}.{1}' inside the call to '{2}' in the application startup code.
/// </summary>
internal static string UnableToFindServices
{
get { return GetString("UnableToFindServices"); }
}
/// <summary>
/// Unable to find the required services. Please add all the required services by calling '{0}.{1}' inside the call to '{2}' in the application startup code.
/// </summary>
internal static string FormatUnableToFindServices(object p0, object p1, object p2)
{
return string.Format(CultureInfo.CurrentCulture, GetString("UnableToFindServices"), p0, p1, p2);
}
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);

View File

@ -195,4 +195,7 @@
<data name="AttributeRoute_DifferentLinkGenerationEntries_SameName" xml:space="preserve">
<value>Two or more routes named '{0}' have different templates.</value>
</data>
<data name="UnableToFindServices" xml:space="preserve">
<value>Unable to find the required services. Please add all the required services by calling '{0}.{1}' inside the call to '{2}' in the application startup code.</value>
</data>
</root>

View File

@ -4,6 +4,8 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Routing.Internal;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNet.Routing
{
@ -21,6 +23,14 @@ namespace Microsoft.AspNet.Routing
throw new ArgumentNullException(nameof(applicationBuilder));
}
if (applicationBuilder.ApplicationServices.GetService(typeof(RoutingMarkerService)) == null)
{
throw new InvalidOperationException(Resources.FormatUnableToFindServices(
nameof(IServiceCollection),
nameof(RoutingServiceCollectionExtensions.AddRouting),
"ConfigureServices(...)"));
}
ApplicationBuilder = applicationBuilder;
ServiceProvider = applicationBuilder.ApplicationServices;

View File

@ -0,0 +1,35 @@
// 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.AspNet.Routing;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Builder
{
public class BuilderExtensionsTest
{
[Fact]
public void UseRouter_ThrowsInvalidOperationException_IfRoutingMarkerServiceIsNotRegistered()
{
// Arrange
var applicationBuilderMock = new Mock<IApplicationBuilder>();
applicationBuilderMock
.Setup(s => s.ApplicationServices)
.Returns(Mock.Of<IServiceProvider>());
var router = Mock.Of<IRouter>();
// Act & Assert
var exception = Assert.Throws<InvalidOperationException>(
() => applicationBuilderMock.Object.UseRouter(router));
Assert.Equal(
"Unable to find the required services. Please add all the required services by calling " +
"'IServiceCollection.AddRouting' inside the call to 'ConfigureServices(...)'" +
" in the application startup code.",
exception.Message);
}
}
}

View File

@ -0,0 +1,32 @@
// 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.AspNet.Builder;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Routing
{
public class RouteBuilderTest
{
[Fact]
public void Ctor_ThrowsInvalidOperationException_IfRoutingMarkerServiceIsNotRegistered()
{
// Arrange
var applicationBuilderMock = new Mock<IApplicationBuilder>();
applicationBuilderMock
.Setup(s => s.ApplicationServices)
.Returns(Mock.Of<IServiceProvider>());
// Act & Assert
var exception = Assert.Throws<InvalidOperationException>(() => new RouteBuilder(applicationBuilderMock.Object));
Assert.Equal(
"Unable to find the required services. Please add all the required services by calling " +
"'IServiceCollection.AddRouting' inside the call to 'ConfigureServices(...)'" +
" in the application startup code.",
exception.Message);
}
}
}

View File

@ -9,6 +9,7 @@ using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Routing.Constraints;
using Microsoft.AspNet.Routing.Internal;
using Microsoft.AspNet.Testing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@ -1578,6 +1579,7 @@ namespace Microsoft.AspNet.Routing
{
var services = new ServiceCollection();
services.AddSingleton<IInlineConstraintResolver>(_inlineConstraintResolver);
services.AddSingleton<RoutingMarkerService>();
var applicationBuilder = Mock.Of<IApplicationBuilder>();
applicationBuilder.ApplicationServices = services.BuildServiceProvider();

View File

@ -3,6 +3,7 @@
using System;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Routing.Internal;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Moq;
@ -112,6 +113,7 @@ namespace Microsoft.AspNet.Routing.Tests
{
var services = new ServiceCollection();
services.AddSingleton<IInlineConstraintResolver>(_inlineConstraintResolver);
services.AddSingleton<RoutingMarkerService>();
var applicationBuilder = Mock.Of<IApplicationBuilder>();
applicationBuilder.ApplicationServices = services.BuildServiceProvider();