[Fixes #3907] Improve MVC error when MVC services aren't registered
This commit is contained in:
parent
c7f6ed4445
commit
82381d97c2
|
|
@ -2,10 +2,12 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNet.Mvc.Core;
|
||||
using Microsoft.AspNet.Mvc.Infrastructure;
|
||||
using Microsoft.AspNet.Mvc.Internal;
|
||||
using Microsoft.AspNet.Mvc.Routing;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNet.Builder
|
||||
{
|
||||
|
|
@ -77,7 +79,13 @@ namespace Microsoft.AspNet.Builder
|
|||
|
||||
// Verify if AddMvc was done before calling UseMvc
|
||||
// We use the MvcMarkerService to make sure if all the services were added.
|
||||
MvcServicesHelper.ThrowIfMvcNotRegistered(app.ApplicationServices);
|
||||
if (app.ApplicationServices.GetService(typeof(MvcMarkerService)) == null)
|
||||
{
|
||||
throw new InvalidOperationException(Resources.FormatUnableToFindServices(
|
||||
nameof(IServiceCollection),
|
||||
"AddMvc",
|
||||
"ConfigureServices(...)"));
|
||||
}
|
||||
|
||||
var routes = new RouteBuilder(app)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -119,10 +119,6 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
|||
|
||||
var services = context.RequestServices;
|
||||
|
||||
// Verify if AddMvc was done before calling UseMvc
|
||||
// We use the MvcMarkerService to make sure if all the services were added.
|
||||
MvcServicesHelper.ThrowIfMvcNotRegistered(services);
|
||||
|
||||
// The IActionContextAccessor is optional. We want to avoid the overhead of using CallContext
|
||||
// if possible.
|
||||
_actionContextAccessor = services.GetService<IActionContextAccessor>();
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
// 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.Mvc.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a Marker class which is used to determine if all the services were added
|
||||
/// to when Mvc is loaded.
|
||||
/// A marker class used to determine if all the MVC services were added
|
||||
/// to the <see cref="IServiceCollection"/> before MVC is configured.
|
||||
/// </summary>
|
||||
public class MvcMarkerService
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,30 +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 System;
|
||||
using Microsoft.AspNet.Mvc.Core;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class which contains MvcServices related helpers.
|
||||
/// </summary>
|
||||
public static class MvcServicesHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Throws InvalidOperationException when MvcMarkerService is not present
|
||||
/// in the list of services.
|
||||
/// </summary>
|
||||
/// <param name="services">The list of services.</param>
|
||||
public static void ThrowIfMvcNotRegistered(IServiceProvider services)
|
||||
{
|
||||
if (services.GetService(typeof(MvcMarkerService)) == null)
|
||||
{
|
||||
throw new InvalidOperationException(Resources.FormatUnableToFindServices(
|
||||
"IServiceCollection.AddMvc()",
|
||||
"IApplicationBuilder.ConfigureServices(...)",
|
||||
"IApplicationBuilder.UseMvc(...)"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -475,7 +475,7 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unable to find the required services. Please add all the required services by calling '{0}' inside the call to '{1}' or '{2}' in the application startup code.
|
||||
/// Unable to find the required services. Please add all the required services by calling '{0}.{1}' inside the call to '{4}' in the application startup code.
|
||||
/// </summary>
|
||||
internal static string UnableToFindServices
|
||||
{
|
||||
|
|
@ -483,11 +483,11 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unable to find the required services. Please add all the required services by calling '{0}' inside the call to '{1}' or '{2}' in the application startup code.
|
||||
/// Unable to find the required services. Please add all the required services by calling '{0}.{1}' inside the call to '{4}' in the application startup code.
|
||||
/// </summary>
|
||||
internal static string FormatUnableToFindServices(object p0, object p1, object p2)
|
||||
internal static string FormatUnableToFindServices(object p0, object p1, object p4)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("UnableToFindServices"), p0, p1, p2);
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("UnableToFindServices"), p0, p1, p4);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@
|
|||
<value>An unescaped '[' token is not allowed inside of a replacement token. Use '[[' to escape.</value>
|
||||
</data>
|
||||
<data name="UnableToFindServices" xml:space="preserve">
|
||||
<value>Unable to find the required services. Please add all the required services by calling '{0}' inside the call to '{1}' or '{2}' in the application startup code.</value>
|
||||
<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>
|
||||
<data name="AttributeRoute_DuplicateNames_Item" xml:space="preserve">
|
||||
<value>Action: '{0}' - Template: '{1}'</value>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Core.Builder
|
||||
{
|
||||
public class MvcApplicationBuilderExtensionsTest
|
||||
{
|
||||
[Fact]
|
||||
public void UseMvc_ThrowsInvalidOperationException_IfMvcMarkerServiceIsNotRegistered()
|
||||
{
|
||||
// Arrange
|
||||
var applicationBuilderMock = new Mock<IApplicationBuilder>();
|
||||
applicationBuilderMock
|
||||
.Setup(s => s.ApplicationServices)
|
||||
.Returns(Mock.Of<IServiceProvider>());
|
||||
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<InvalidOperationException>(
|
||||
() => applicationBuilderMock.Object.UseMvc(rb => { }));
|
||||
|
||||
Assert.Equal(
|
||||
"Unable to find the required services. Please add all the required services by calling " +
|
||||
"'IServiceCollection.AddMvc' inside the call to 'ConfigureServices(...)' " +
|
||||
"in the application startup code.",
|
||||
exception.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,44 +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 System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNet.Mvc.Internal;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class MvcServicesHelperTests
|
||||
{
|
||||
[Fact]
|
||||
public void MvcServicesHelperThrowsIfServiceIsAbsent()
|
||||
{
|
||||
// Arrange
|
||||
var services = new Mock<IServiceProvider>();
|
||||
services.Setup(o => o.GetService(typeof(IEnumerable<MvcMarkerService>)))
|
||||
.Returns(new List<MvcMarkerService>());
|
||||
var expectedMessage = "Unable to find the required services. Please add all the required " +
|
||||
"services by calling 'IServiceCollection.AddMvc()' inside the call to 'IApplicationBuilder.ConfigureServices(...)' " +
|
||||
"or 'IApplicationBuilder.UseMvc(...)' in the application startup code.";
|
||||
|
||||
// Act & Assert
|
||||
var ex = Assert.Throws<InvalidOperationException>(
|
||||
() => MvcServicesHelper.ThrowIfMvcNotRegistered(services.Object));
|
||||
Assert.Equal(expectedMessage, ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MvcServicesHelperDoesNotThrowIfServiceExists()
|
||||
{
|
||||
// Arrange
|
||||
var services = new Mock<IServiceProvider>();
|
||||
var expectedOutput = new MvcMarkerService();
|
||||
services.Setup(o => o.GetService(typeof(MvcMarkerService)))
|
||||
.Returns(expectedOutput);
|
||||
|
||||
// Act & Assert (does not throw)
|
||||
MvcServicesHelper.ThrowIfMvcNotRegistered(services.Object);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue