diff --git a/src/Microsoft.AspNet.Hosting/HostingServices.cs b/src/Microsoft.AspNet.Hosting/HostingServices.cs index dbf5c26adc..f1ce9b3cd2 100644 --- a/src/Microsoft.AspNet.Hosting/HostingServices.cs +++ b/src/Microsoft.AspNet.Hosting/HostingServices.cs @@ -9,6 +9,7 @@ using Microsoft.AspNet.Security.DataProtection; using Microsoft.Framework.ConfigurationModel; using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.Logging; +using Microsoft.Framework.OptionsModel; namespace Microsoft.AspNet.Hosting { @@ -41,6 +42,11 @@ namespace Microsoft.AspNet.Hosting yield return describer.Scoped(typeof(IContextAccessor<>), typeof(ContextAccessor<>)); + foreach (var service in OptionsServices.GetDefaultServices()) + { + yield return service; + } + foreach (var service in DataProtectionServices.GetDefaultServices()) { yield return service; diff --git a/src/Microsoft.AspNet.Hosting/Program.cs b/src/Microsoft.AspNet.Hosting/Program.cs index 801041bdc0..5d83450f4d 100644 --- a/src/Microsoft.AspNet.Hosting/Program.cs +++ b/src/Microsoft.AspNet.Hosting/Program.cs @@ -50,7 +50,7 @@ namespace Microsoft.AspNet.Hosting // The application name is a "good enough" mechanism to identify this application // on the machine and to prevent subkeys from being shared across multiple applications // by default. - serviceCollection.ConfigureOptions(options => + serviceCollection.Configure(options => { options.ApplicationDiscriminator = appEnv.ApplicationName; }); diff --git a/src/Microsoft.AspNet.Hosting/Startup/StartupLoader.cs b/src/Microsoft.AspNet.Hosting/Startup/StartupLoader.cs index fd4756cb54..7658009466 100644 --- a/src/Microsoft.AspNet.Hosting/Startup/StartupLoader.cs +++ b/src/Microsoft.AspNet.Hosting/Startup/StartupLoader.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Reflection; using Microsoft.AspNet.Builder; @@ -27,16 +28,17 @@ namespace Microsoft.AspNet.Hosting.Startup private MethodInfo FindMethod(Type startupType, string methodName, string environmentName, Type returnType = null, bool required = true) { - var methodNameWithEnv = methodName + environmentName; + var methodNameWithEnv = string.Format(CultureInfo.InvariantCulture, methodName, environmentName); + var methodNameWithNoEnv = string.Format(CultureInfo.InvariantCulture, methodName, ""); var methodInfo = startupType.GetTypeInfo().GetDeclaredMethod(methodNameWithEnv) - ?? startupType.GetTypeInfo().GetDeclaredMethod(methodName); + ?? startupType.GetTypeInfo().GetDeclaredMethod(methodNameWithNoEnv); if (methodInfo == null) { if (required) { throw new Exception(string.Format("TODO: {0} or {1} method not found", methodNameWithEnv, - methodName)); + methodNameWithNoEnv)); } return null; @@ -134,9 +136,9 @@ namespace Microsoft.AspNet.Hosting.Startup applicationName)); } - var configureMethod = FindMethod(type, "Configure", environmentName, typeof(void), required: true); + var configureMethod = FindMethod(type, "Configure{0}", environmentName, typeof(void), required: true); // TODO: accept IServiceProvider method as well? - var servicesMethod = FindMethod(type, "ConfigureServices", environmentName, typeof(void), required: false); + var servicesMethod = FindMethod(type, "Configure{0}Services", environmentName, typeof(void), required: false); object instance = null; if (!configureMethod.IsStatic || (servicesMethod != null && !servicesMethod.IsStatic)) diff --git a/src/Microsoft.AspNet.RequestContainer/ContainerExtensions.cs b/src/Microsoft.AspNet.RequestContainer/ContainerExtensions.cs index 5494e86edc..fbd5f08ea4 100644 --- a/src/Microsoft.AspNet.RequestContainer/ContainerExtensions.cs +++ b/src/Microsoft.AspNet.RequestContainer/ContainerExtensions.cs @@ -31,33 +31,33 @@ namespace Microsoft.AspNet.Builder }); } - public static IApplicationBuilder UsePerRequestServices(this IApplicationBuilder builder) + public static IApplicationBuilder UseRequestServices(this IApplicationBuilder builder) { return builder.UseMiddleware(typeof(ContainerMiddleware)); } - public static IApplicationBuilder UsePerRequestServices(this IApplicationBuilder builder, IServiceProvider applicationServices) + public static IApplicationBuilder UseRequestServices(this IApplicationBuilder builder, IServiceProvider applicationServices) { builder.ApplicationServices = applicationServices; return builder.UseMiddleware(typeof(ContainerMiddleware)); } - public static IApplicationBuilder UsePerRequestServices(this IApplicationBuilder builder, IEnumerable applicationServices) + public static IApplicationBuilder UseServices(this IApplicationBuilder builder, IEnumerable applicationServices) { - return builder.UsePerRequestServices(services => services.Add(applicationServices)); + return builder.UseServices(services => services.Add(applicationServices)); } - public static IApplicationBuilder UsePerRequestServices(this IApplicationBuilder builder, Action configureServices) + public static IApplicationBuilder UseServices(this IApplicationBuilder builder, Action configureServices) { - return builder.UsePerRequestServices(serviceCollection => + return builder.UseServices(serviceCollection => { configureServices(serviceCollection); return serviceCollection.BuildServiceProvider(builder.ApplicationServices); }); } - public static IApplicationBuilder UsePerRequestServices(this IApplicationBuilder builder, Func configureServices) + public static IApplicationBuilder UseServices(this IApplicationBuilder builder, Func configureServices) { var serviceCollection = new ServiceCollection(); diff --git a/src/Microsoft.AspNet.RequestContainer/ContainerMiddleware.cs b/src/Microsoft.AspNet.RequestContainer/ContainerMiddleware.cs index 706b14294a..3c1e5e52c9 100644 --- a/src/Microsoft.AspNet.RequestContainer/ContainerMiddleware.cs +++ b/src/Microsoft.AspNet.RequestContainer/ContainerMiddleware.cs @@ -49,7 +49,7 @@ namespace Microsoft.AspNet.RequestContainer _rootHttpContextAccessor.SetContextSource(AccessRootHttpContext, ExchangeRootHttpContext); } - private HttpContext AccessRootHttpContext() + internal static HttpContext AccessRootHttpContext() { #if ASPNET50 var handle = CallContext.LogicalGetData(LogicalDataKey) as ObjectHandle; @@ -59,7 +59,7 @@ namespace Microsoft.AspNet.RequestContainer #endif } - private HttpContext ExchangeRootHttpContext(HttpContext httpContext) + internal static HttpContext ExchangeRootHttpContext(HttpContext httpContext) { #if ASPNET50 var prior = CallContext.LogicalGetData(LogicalDataKey) as ObjectHandle; @@ -92,29 +92,9 @@ namespace Microsoft.AspNet.RequestContainer appHttpContextAccessor = priorApplicationServices.GetService>(); } - using (var scope = appServiceScopeFactory.CreateScope()) + using (var container = new RequestServicesContainer(httpContext, appServiceScopeFactory, appHttpContextAccessor, appServiceProvider)) { - var scopeServiceProvider = scope.ServiceProvider; - var scopeHttpContextAccessor = scopeServiceProvider.GetService>(); - - httpContext.ApplicationServices = appServiceProvider; - httpContext.RequestServices = scopeServiceProvider; - - var priorAppHttpContext = appHttpContextAccessor.SetValue(httpContext); - var priorScopeHttpContext = scopeHttpContextAccessor.SetValue(httpContext); - - try - { - await _next.Invoke(httpContext); - } - finally - { - scopeHttpContextAccessor.SetValue(priorScopeHttpContext); - appHttpContextAccessor.SetValue(priorAppHttpContext); - - httpContext.RequestServices = priorRequestServices; - httpContext.ApplicationServices = priorApplicationServices; - } + await _next.Invoke(httpContext); } } } diff --git a/src/Microsoft.AspNet.RequestContainer/RequestServicesContainer.cs b/src/Microsoft.AspNet.RequestContainer/RequestServicesContainer.cs new file mode 100644 index 0000000000..c4bbf142c2 --- /dev/null +++ b/src/Microsoft.AspNet.RequestContainer/RequestServicesContainer.cs @@ -0,0 +1,142 @@ +// Copyright (c) Microsoft Open Technologies, Inc. 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.Http; +using Microsoft.Framework.DependencyInjection; + +namespace Microsoft.AspNet.RequestContainer +{ + public class RequestServicesContainer : IDisposable + { + public RequestServicesContainer( + HttpContext context, + IServiceScopeFactory scopeFactory, + IContextAccessor appContextAccessor, + IServiceProvider appServiceProvider) + { + if (scopeFactory == null) + { + throw new ArgumentNullException(nameof(scopeFactory)); + } + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + if (appContextAccessor == null) + { + throw new ArgumentNullException(nameof(appContextAccessor)); + } + + AppContextAccessor = appContextAccessor; + + Context = context; + PriorAppServices = context.ApplicationServices; + PriorRequestServices = context.RequestServices; + + // Begin the scope + Scope = scopeFactory.CreateScope(); + ScopeContextAccessor = Scope.ServiceProvider.GetService>(); + + Context.ApplicationServices = appServiceProvider; + Context.RequestServices = Scope.ServiceProvider; + + PriorAppHttpContext = AppContextAccessor.SetValue(context); + PriorScopeHttpContext = ScopeContextAccessor.SetValue(context); + } + + private HttpContext Context { get; set; } + private IServiceProvider PriorAppServices { get; set; } + private IServiceProvider PriorRequestServices { get; set; } + private HttpContext PriorAppHttpContext { get; set; } + private HttpContext PriorScopeHttpContext { get; set; } + private IServiceScope Scope { get; set; } + private IContextAccessor ScopeContextAccessor { get; set; } + private IContextAccessor AppContextAccessor { get; set; } + + // CONSIDER: this could be an extension method on HttpContext instead + public static RequestServicesContainer EnsureRequestServices(HttpContext httpContext) + { + // All done if we already have a request services + if (httpContext.RequestServices != null) + { + return null; + } + + if (httpContext.ApplicationServices == null) + { + throw new InvalidOperationException("TODO: httpContext.ApplicationServices is null!"); + } + + // Matches constructor of RequestContainer + var rootServiceProvider = httpContext.ApplicationServices.GetService(); + var rootHttpContextAccessor = httpContext.ApplicationServices.GetService>(); + var rootServiceScopeFactory = httpContext.ApplicationServices.GetService(); + + rootHttpContextAccessor.SetContextSource(ContainerMiddleware.AccessRootHttpContext, ContainerMiddleware.ExchangeRootHttpContext); + + // Pre Scope setup + var priorApplicationServices = httpContext.ApplicationServices; + var priorRequestServices = httpContext.RequestServices; + + var appServiceProvider = rootServiceProvider; + var appServiceScopeFactory = rootServiceScopeFactory; + var appHttpContextAccessor = rootHttpContextAccessor; + + if (priorApplicationServices != null && + priorApplicationServices != appServiceProvider) + { + appServiceProvider = priorApplicationServices; + appServiceScopeFactory = priorApplicationServices.GetService(); + appHttpContextAccessor = priorApplicationServices.GetService>(); + } + + // Creates the scope and does the service swaps + return new RequestServicesContainer(httpContext, appServiceScopeFactory, appHttpContextAccessor, appServiceProvider); + } + + #region IDisposable Support + private bool disposedValue = false; // To detect redundant calls + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + ScopeContextAccessor.SetValue(PriorScopeHttpContext); + AppContextAccessor.SetValue(PriorAppHttpContext); + + Context.RequestServices = PriorRequestServices; + Context.ApplicationServices = PriorAppServices; + } + + if (Scope != null) + { + Scope.Dispose(); + Scope = null; + } + + Context = null; + PriorAppServices = null; + PriorRequestServices = null; + ScopeContextAccessor = null; + AppContextAccessor = null; + PriorAppHttpContext = null; + PriorScopeHttpContext = null; + + disposedValue = true; + } + } + + // This code added to correctly implement the disposable pattern. + public void Dispose() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(true); + } + #endregion + + } + +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Hosting.Tests/Fakes/FakeOptions.cs b/test/Microsoft.AspNet.Hosting.Tests/Fakes/FakeOptions.cs index d3c7ee2b0b..a955ed377e 100644 --- a/test/Microsoft.AspNet.Hosting.Tests/Fakes/FakeOptions.cs +++ b/test/Microsoft.AspNet.Hosting.Tests/Fakes/FakeOptions.cs @@ -7,5 +7,6 @@ namespace Microsoft.AspNet.Hosting.Fakes { public bool Configured { get; set; } public string Environment { get; set; } + public string Message { get; set; } } } \ No newline at end of file diff --git a/test/Microsoft.AspNet.Hosting.Tests/Fakes/IFakeService.cs b/test/Microsoft.AspNet.Hosting.Tests/Fakes/IFakeService.cs new file mode 100644 index 0000000000..e183e13eb2 --- /dev/null +++ b/test/Microsoft.AspNet.Hosting.Tests/Fakes/IFakeService.cs @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNet.Hosting.Fakes +{ + public interface IFakeService { } + public class FakeService : IFakeService { } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Hosting.Tests/Fakes/Startup.cs b/test/Microsoft.AspNet.Hosting.Tests/Fakes/Startup.cs index 2fa43ea158..6f97e4ceda 100644 --- a/test/Microsoft.AspNet.Hosting.Tests/Fakes/Startup.cs +++ b/test/Microsoft.AspNet.Hosting.Tests/Fakes/Startup.cs @@ -14,37 +14,37 @@ namespace Microsoft.AspNet.Hosting.Fakes public void ConfigureServices(IServiceCollection services) { - services.ConfigureOptions(o => o.Configured = true); + services.Configure(o => o.Configured = true); } - public void ConfigureServicesDev(IServiceCollection services) + public void ConfigureDevServices(IServiceCollection services) { - services.ConfigureOptions(o => + services.Configure(o => { o.Configured = true; o.Environment = "Dev"; }); } - public void ConfigureServicesRetail(IServiceCollection services) + public void ConfigureRetailServices(IServiceCollection services) { - services.ConfigureOptions(o => + services.Configure(o => { o.Configured = true; o.Environment = "Retail"; }); } - public static void ConfigureServicesStatic(IServiceCollection services) + public static void ConfigureStaticServices(IServiceCollection services) { - services.ConfigureOptions(o => + services.Configure(o => { o.Configured = true; o.Environment = "Static"; }); } - public void Configure(IApplicationBuilder builder) + public virtual void Configure(IApplicationBuilder builder) { } } diff --git a/test/Microsoft.AspNet.Hosting.Tests/Fakes/StartupBoom.cs b/test/Microsoft.AspNet.Hosting.Tests/Fakes/StartupBoom.cs new file mode 100644 index 0000000000..6fb647a489 --- /dev/null +++ b/test/Microsoft.AspNet.Hosting.Tests/Fakes/StartupBoom.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNet.Hosting.Fakes +{ + public class StartupBoom + { + public StartupBoom() + { + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Hosting.Tests/Fakes/StartupUseServices.cs b/test/Microsoft.AspNet.Hosting.Tests/Fakes/StartupUseServices.cs new file mode 100644 index 0000000000..bfd85da550 --- /dev/null +++ b/test/Microsoft.AspNet.Hosting.Tests/Fakes/StartupUseServices.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNet.Builder; +using Microsoft.Framework.DependencyInjection; + +namespace Microsoft.AspNet.Hosting.Fakes +{ + public class StartupUseServices + { + public StartupUseServices() + { + } + + public void ConfigureUseServicesServices(IServiceCollection services) + { + services.Configure(o => o.Configured = true); + services.AddTransient(); + } + + public void Configure(IApplicationBuilder builder) + { + builder.UseServices(services => + { + services.AddTransient(); + services.Configure(o => o.Message = "Configured"); + }); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Hosting.Tests/Microsoft.AspNet.Hosting.Tests.kproj b/test/Microsoft.AspNet.Hosting.Tests/Microsoft.AspNet.Hosting.Tests.kproj index d20ea65b15..0b04b9270d 100644 --- a/test/Microsoft.AspNet.Hosting.Tests/Microsoft.AspNet.Hosting.Tests.kproj +++ b/test/Microsoft.AspNet.Hosting.Tests/Microsoft.AspNet.Hosting.Tests.kproj @@ -16,6 +16,7 @@ 2.0 + 29216 \ No newline at end of file diff --git a/test/Microsoft.AspNet.Hosting.Tests/StartupManagerTests.cs b/test/Microsoft.AspNet.Hosting.Tests/StartupManagerTests.cs index d84773ad76..2d73f17c22 100644 --- a/test/Microsoft.AspNet.Hosting.Tests/StartupManagerTests.cs +++ b/test/Microsoft.AspNet.Hosting.Tests/StartupManagerTests.cs @@ -53,14 +53,37 @@ namespace Microsoft.AspNet.Hosting startup.Invoke(app); - var options = app.ApplicationServices.GetService>().Options; + var options = app.ApplicationServices.GetService>().Options; Assert.NotNull(options); Assert.True(options.Configured); Assert.Equal(environment, options.Environment); } - [Fact(Skip = "DataProtection registers default Options services; need to figure out what to do with this test.")] - public void StartupClassDoesNotRegisterOptionsWithNoConfigureServices() + [Fact] + public void StartupClassWithConfigureServicesAndUseServicesAddsBothToServices() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.Add(HostingServices.GetDefaultServices()); + var services = serviceCollection.BuildServiceProvider(); + var manager = services.GetService(); + + var startup = manager.LoadStartup("Microsoft.AspNet.Hosting.Tests", "UseServices"); + + var app = new ApplicationBuilder(services); + + startup.Invoke(app); + + Assert.NotNull(app.ApplicationServices.GetService()); + Assert.NotNull(app.ApplicationServices.GetService()); + + var options = app.ApplicationServices.GetService>().Options; + Assert.NotNull(options); + Assert.Equal("Configured", options.Message); + Assert.False(options.Configured); // REVIEW: why doesn't the ConfigureServices ConfigureOptions get run? + } + + [Fact] + public void StartupWithNoConfigureThrows() { var serviceCollection = new ServiceCollection(); serviceCollection.Add(HostingServices.GetDefaultServices()); @@ -68,14 +91,8 @@ namespace Microsoft.AspNet.Hosting var services = serviceCollection.BuildServiceProvider(); var manager = services.GetService(); - var startup = manager.LoadStartup("Microsoft.AspNet.Hosting.Tests", "NoServices"); - - var app = new ApplicationBuilder(services); - - startup.Invoke(app); - - var ex = Assert.Throws(() => app.ApplicationServices.GetService>()); - Assert.True(ex.Message.Contains("No service for type 'Microsoft.Framework.OptionsModel.IOptionsAccessor")); + var ex = Assert.Throws(() => manager.LoadStartup("Microsoft.AspNet.Hosting.Tests", "Boom")); + Assert.True(ex.Message.Contains("ConfigureBoom or Configure method not found")); } public void ConfigurationMethodCalled(object instance) diff --git a/test/Microsoft.AspNet.Hosting.Tests/UseRequestServicesFacts.cs b/test/Microsoft.AspNet.Hosting.Tests/UseRequestServicesFacts.cs new file mode 100644 index 0000000000..597c286054 --- /dev/null +++ b/test/Microsoft.AspNet.Hosting.Tests/UseRequestServicesFacts.cs @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNet.Builder; +using Microsoft.Framework.DependencyInjection; +using Microsoft.Framework.DependencyInjection.Fallback; +using Xunit; +using Microsoft.AspNet.PipelineCore; +using Microsoft.AspNet.RequestContainer; + +namespace Microsoft.AspNet.Hosting.Tests +{ + public class RequestServicesContainerFacts + { + [Fact] + public void RequestServicesAvailableOnlyAfterRequestServices() + { + var baseServiceProvider = new ServiceCollection() + .Add(HostingServices.GetDefaultServices()) + .BuildServiceProvider(); + var builder = new ApplicationBuilder(baseServiceProvider); + + bool foundRequestServicesBefore = false; + builder.Use(next => async c => + { + foundRequestServicesBefore = c.RequestServices != null; + await next.Invoke(c); + }); + builder.UseRequestServices(); + bool foundRequestServicesAfter = false; + builder.Use(next => async c => + { + foundRequestServicesAfter = c.RequestServices != null; + await next.Invoke(c); + }); + + var context = new DefaultHttpContext(); + builder.Build().Invoke(context); + Assert.False(foundRequestServicesBefore); + Assert.True(foundRequestServicesAfter); + } + + [Fact] + public void EnsureRequestServicesSetsRequestServices() + { + var baseServiceProvider = new ServiceCollection() + .Add(HostingServices.GetDefaultServices()) + .BuildServiceProvider(); + var builder = new ApplicationBuilder(baseServiceProvider); + + bool foundRequestServicesBefore = false; + builder.Use(next => async c => + { + foundRequestServicesBefore = c.RequestServices != null; + await next.Invoke(c); + }); + builder.Use(next => async c => + { + using (var container = RequestServicesContainer.EnsureRequestServices(c)) + { + await next.Invoke(c); + } + }); + bool foundRequestServicesAfter = false; + builder.Use(next => async c => + { + foundRequestServicesAfter = c.RequestServices != null; + await next.Invoke(c); + }); + + var context = new DefaultHttpContext(); + context.ApplicationServices = baseServiceProvider; + builder.Build().Invoke(context); + Assert.False(foundRequestServicesBefore); + Assert.True(foundRequestServicesAfter); + } + + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Hosting.Tests/UseServicesFacts.cs b/test/Microsoft.AspNet.Hosting.Tests/UseServicesFacts.cs index 2dae3babea..f32a45af49 100644 --- a/test/Microsoft.AspNet.Hosting.Tests/UseServicesFacts.cs +++ b/test/Microsoft.AspNet.Hosting.Tests/UseServicesFacts.cs @@ -7,6 +7,8 @@ using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.DependencyInjection.Fallback; using Microsoft.Framework.OptionsModel; using Xunit; +using Microsoft.AspNet.Http; +using Microsoft.AspNet.PipelineCore; namespace Microsoft.AspNet.Hosting.Tests { @@ -18,9 +20,9 @@ namespace Microsoft.AspNet.Hosting.Tests var baseServiceProvider = new ServiceCollection().BuildServiceProvider(); var builder = new ApplicationBuilder(baseServiceProvider); - builder.UsePerRequestServices(serviceCollection => { }); + builder.UseServices(serviceCollection => { }); - var optionsAccessor = builder.ApplicationServices.GetService>(); + var optionsAccessor = builder.ApplicationServices.GetService>(); Assert.NotNull(optionsAccessor); } @@ -32,14 +34,14 @@ namespace Microsoft.AspNet.Hosting.Tests var builder = new ApplicationBuilder(baseServiceProvider); IServiceProvider serviceProvider = null; - builder.UsePerRequestServices(serviceCollection => + builder.UseServices(serviceCollection => { serviceProvider = serviceCollection.BuildServiceProvider(builder.ApplicationServices); return serviceProvider; }); Assert.Same(serviceProvider, builder.ApplicationServices); - var optionsAccessor = builder.ApplicationServices.GetService>(); + var optionsAccessor = builder.ApplicationServices.GetService>(); Assert.NotNull(optionsAccessor); } } diff --git a/test/Microsoft.AspNet.TestHost.Tests/Microsoft.AspNet.TestHost.Tests.kproj b/test/Microsoft.AspNet.TestHost.Tests/Microsoft.AspNet.TestHost.Tests.kproj index 777a4d4460..53d92fe14b 100644 --- a/test/Microsoft.AspNet.TestHost.Tests/Microsoft.AspNet.TestHost.Tests.kproj +++ b/test/Microsoft.AspNet.TestHost.Tests/Microsoft.AspNet.TestHost.Tests.kproj @@ -16,6 +16,7 @@ 2.0 + 29215 \ No newline at end of file