Skip to content
This repository has been archived by the owner on Dec 19, 2018. It is now read-only.

Create a scoped service provider for the call to Configure #1106

Merged
merged 2 commits into from
Jun 19, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
45 changes: 25 additions & 20 deletions src/Microsoft.AspNetCore.Hosting/Internal/ConfigureBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,34 +21,39 @@ public ConfigureBuilder(MethodInfo configure)

private void Invoke(object instance, IApplicationBuilder builder)
{
var serviceProvider = builder.ApplicationServices;
var parameterInfos = MethodInfo.GetParameters();
var parameters = new object[parameterInfos.Length];
for (var index = 0; index < parameterInfos.Length; index++)
// Create a scope for Configure, this allows creating scoped dependencies
// without the hassle of manually creating a scope.
using (var scope = builder.ApplicationServices.CreateScope())
{
var parameterInfo = parameterInfos[index];
if (parameterInfo.ParameterType == typeof(IApplicationBuilder))
var serviceProvider = scope.ServiceProvider;
var parameterInfos = MethodInfo.GetParameters();
var parameters = new object[parameterInfos.Length];
for (var index = 0; index < parameterInfos.Length; index++)
{
parameters[index] = builder;
}
else
{
try
var parameterInfo = parameterInfos[index];
if (parameterInfo.ParameterType == typeof(IApplicationBuilder))
{
parameters[index] = serviceProvider.GetRequiredService(parameterInfo.ParameterType);
parameters[index] = builder;
}
catch (Exception ex)
else
{
throw new Exception(string.Format(
"Could not resolve a service of type '{0}' for the parameter '{1}' of method '{2}' on type '{3}'.",
parameterInfo.ParameterType.FullName,
parameterInfo.Name,
MethodInfo.Name,
MethodInfo.DeclaringType.FullName), ex);
try
{
parameters[index] = serviceProvider.GetRequiredService(parameterInfo.ParameterType);
}
catch (Exception ex)
{
throw new Exception(string.Format(
"Could not resolve a service of type '{0}' for the parameter '{1}' of method '{2}' on type '{3}'.",
parameterInfo.ParameterType.FullName,
parameterInfo.Name,
MethodInfo.Name,
MethodInfo.DeclaringType.FullName), ex);
}
}
}
MethodInfo.Invoke(instance, parameters);
}
MethodInfo.Invoke(instance, parameters);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Builder;
using static Microsoft.AspNetCore.Hosting.Tests.StartupManagerTests;

namespace Microsoft.AspNetCore.Hosting.Tests.Fakes
{
public class StartupWithScopedServices
{
public void Configure(IApplicationBuilder builder, DisposableService disposable)
{

}
}
}
30 changes: 30 additions & 0 deletions test/Microsoft.AspNetCore.Hosting.Tests/StartupManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,26 @@ public void StartupClassMayHaveHostingServicesInjected()
Assert.Equal(2, callbackStartup.MethodsCalled);
}

[Fact]
public void StartupClassMayHaveScopedServicesInjected()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<IServiceProviderFactory<IServiceCollection>>(new DefaultServiceProviderFactory(new ServiceProviderOptions
{
ValidateScopes = true
}));

serviceCollection.AddScoped<DisposableService>();
var services = serviceCollection.BuildServiceProvider();

var type = StartupLoader.FindStartupType("Microsoft.AspNetCore.Hosting.Tests", "WithScopedServices");
var startup = StartupLoader.LoadMethods(services, type, "WithScopedServices");

var app = new ApplicationBuilder(services);
app.ApplicationServices = startup.ConfigureServicesDelegate(serviceCollection);
startup.ConfigureDelegate(app);
}

[Theory]
[InlineData(null)]
[InlineData("Dev")]
Expand Down Expand Up @@ -405,5 +425,15 @@ public void ConfigurationMethodCalled(object instance)
_configurationMethodCalledList.Add(instance);
}
}

public class DisposableService : IDisposable
{
public bool Disposed { get; set; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Were you going to use this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, but it's impossible to get to at the instance. I can remove it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixing it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🆙 📅


public void Dispose()
{
Disposed = true;
}
}
}
}