Remove target invocation exceptions from Startup invocation (#9318)

- This change takes advatage of the new DoNotWrapExceptions binding flag to avoid throwing a TargetInvocationException when invoking Configure/ConfigureServices and ConfigureContainer
This commit is contained in:
David Fowler 2019-04-12 08:26:42 -07:00 committed by GitHub
parent 0d45fe73d7
commit 717fa39167
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 60 additions and 10 deletions

View File

@ -268,7 +268,7 @@ namespace Microsoft.AspNetCore.Hosting.Internal
// _builder.ConfigureContainer<T>(ConfigureContainer);
typeof(IHostBuilder).GetMethods().First(m => m.Name == nameof(IHostBuilder.ConfigureContainer))
.MakeGenericMethod(containerType)
.Invoke(_builder, new object[] { configureCallback });
.InvokeWithoutWrappingExceptions(_builder, new object[] { configureCallback });
}
// Resolve Configure after calling ConfigureServices and ConfigureContainer

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Globalization;
using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
@ -52,8 +53,9 @@ namespace Microsoft.AspNetCore.Hosting.Internal
}
}
}
MethodInfo.Invoke(instance, parameters);
MethodInfo.InvokeWithoutWrappingExceptions(instance, parameters);
}
}
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// 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;
@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Hosting.Internal
var arguments = new object[1] { container };
MethodInfo.Invoke(instance, arguments);
MethodInfo.InvokeWithoutWrappingExceptions(instance, arguments);
}
}
}
}

View File

@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.Hosting.Internal
arguments[0] = services;
}
return MethodInfo.Invoke(instance, arguments) as IServiceProvider;
return MethodInfo.InvokeWithoutWrappingExceptions(instance, arguments) as IServiceProvider;
}
}
}
}

View File

@ -0,0 +1,20 @@
// 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.Reflection;
namespace Microsoft.AspNetCore.Hosting.Internal
{
internal static class MethodInfoExtensions
{
// This version of MethodInfo.Invoke removes TargetInvocationExceptions
public static object InvokeWithoutWrappingExceptions(this MethodInfo methodInfo, object obj, object[] parameters)
{
// These are the default arguments passed when methodInfo.Invoke(obj, parameters) are called. We do the same
// here but specify BindingFlags.DoNotWrapExceptions to avoid getting TAE (TargetInvocationException)
// methodInfo.Invoke(obj, BindingFlags.Default, binder: null, parameters: parameters, culture: null)
return methodInfo.Invoke(obj, BindingFlags.DoNotWrapExceptions, binder: null, parameters: parameters, culture: null);
}
}
}

View File

@ -500,8 +500,36 @@ namespace Microsoft.AspNetCore.Hosting.Tests
var app = new ApplicationBuilder(services);
app.ApplicationServices = startup.ConfigureServicesDelegate(serviceCollection);
var ex = Assert.Throws<TargetInvocationException>(() => startup.ConfigureDelegate(app));
Assert.IsAssignableFrom<InvalidOperationException>(ex.InnerException);
Assert.Throws<InvalidOperationException>(() => startup.ConfigureDelegate(app));
}
[Fact]
public void ConfigureServicesThrowingDoesNotThrowTargetInvocationException()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<IServiceProviderFactory<IServiceCollection>, DefaultServiceProviderFactory>();
var services = serviceCollection.BuildServiceProvider();
var startup = StartupLoader.LoadMethods(services, typeof(StartupConfigureServicesThrows), environmentName: null);
var app = new ApplicationBuilder(services);
Assert.Throws<Exception>(() => startup.ConfigureServicesDelegate(serviceCollection));
}
[Fact]
public void ConfigureThrowingDoesNotThrowTargetInvocationException()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<IServiceProviderFactory<IServiceCollection>, DefaultServiceProviderFactory>();
var services = serviceCollection.BuildServiceProvider();
var startup = StartupLoader.LoadMethods(services, typeof(StartupConfigureThrows), environmentName: null);
var app = new ApplicationBuilder(services);
app.ApplicationServices = startup.ConfigureServicesDelegate(serviceCollection);
Assert.Throws<Exception>(() => startup.ConfigureDelegate(app));
}
[Fact]