Rework hosting

- IStartupFilter support
- Rework HostingEngine
- AutoRequestScope by default via (IStartupFilter)
- RIP RequestContainer
This commit is contained in:
Hao Kung 2015-03-19 10:57:34 -07:00
parent de44c3be99
commit 19b75b688a
36 changed files with 654 additions and 1082 deletions

View File

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.22530.0
VisualStudioVersion = 14.0.22710.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E0497F39-AFFB-4819-A116-E39E361915AB}"
EndProject
@ -15,8 +15,6 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Hosting",
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Hosting.Tests", "test\Microsoft.AspNet.Hosting.Tests\Microsoft.AspNet.Hosting.Tests.xproj", "{D4F18D58-52B1-435D-A012-10F2CDF158C4}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.RequestContainer", "src\Microsoft.AspNet.RequestContainer\Microsoft.AspNet.RequestContainer.xproj", "{374A5B0C-3E93-4A23-A4A0-EE2AB6DF7814}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A66E3673-3976-4152-B902-2D0EC1428EA2}"
ProjectSection(SolutionItems) = preProject
global.json = global.json
@ -74,16 +72,6 @@ Global
{D4F18D58-52B1-435D-A012-10F2CDF158C4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{D4F18D58-52B1-435D-A012-10F2CDF158C4}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{D4F18D58-52B1-435D-A012-10F2CDF158C4}.Release|x86.ActiveCfg = Release|Any CPU
{374A5B0C-3E93-4A23-A4A0-EE2AB6DF7814}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{374A5B0C-3E93-4A23-A4A0-EE2AB6DF7814}.Debug|Any CPU.Build.0 = Debug|Any CPU
{374A5B0C-3E93-4A23-A4A0-EE2AB6DF7814}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{374A5B0C-3E93-4A23-A4A0-EE2AB6DF7814}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{374A5B0C-3E93-4A23-A4A0-EE2AB6DF7814}.Debug|x86.ActiveCfg = Debug|Any CPU
{374A5B0C-3E93-4A23-A4A0-EE2AB6DF7814}.Release|Any CPU.ActiveCfg = Release|Any CPU
{374A5B0C-3E93-4A23-A4A0-EE2AB6DF7814}.Release|Any CPU.Build.0 = Release|Any CPU
{374A5B0C-3E93-4A23-A4A0-EE2AB6DF7814}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{374A5B0C-3E93-4A23-A4A0-EE2AB6DF7814}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{374A5B0C-3E93-4A23-A4A0-EE2AB6DF7814}.Release|x86.ActiveCfg = Release|Any CPU
{BB780FBB-7842-4759-8DE7-96FA2E5571C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BB780FBB-7842-4759-8DE7-96FA2E5571C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BB780FBB-7842-4759-8DE7-96FA2E5571C1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@ -105,7 +93,6 @@ Global
{1A415A3F-1081-45DB-809B-EE19CEA02DC0} = {E0497F39-AFFB-4819-A116-E39E361915AB}
{3944F036-7E75-47E8-AA52-C4B89A64EC3A} = {E0497F39-AFFB-4819-A116-E39E361915AB}
{D4F18D58-52B1-435D-A012-10F2CDF158C4} = {FEB39027-9158-4DE2-997F-7ADAEF8188D0}
{374A5B0C-3E93-4A23-A4A0-EE2AB6DF7814} = {E0497F39-AFFB-4819-A116-E39E361915AB}
{BB780FBB-7842-4759-8DE7-96FA2E5571C1} = {E0497F39-AFFB-4819-A116-E39E361915AB}
EndGlobalSection
EndGlobal

View File

@ -7,7 +7,7 @@ namespace Microsoft.AspNet.Hosting
{
public interface IHostingEnvironment
{
string EnvironmentName { get; set; }
string EnvironmentName { get; set; }
string WebRootPath { get; }

View File

@ -1,23 +0,0 @@
// 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.Framework.ConfigurationModel;
namespace Microsoft.AspNet.Hosting
{
internal class ConfigureHostingEnvironment : IConfigureHostingEnvironment
{
private IConfiguration _config;
private const string EnvironmentKey = "ASPNET_ENV";
public ConfigureHostingEnvironment(IConfiguration config)
{
_config = config;
}
public void Configure(IHostingEnvironment hostingEnv)
{
hostingEnv.EnvironmentName = _config?.Get(EnvironmentKey) ?? hostingEnv.EnvironmentName;
}
}
}

View File

@ -4,22 +4,29 @@
using System;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting.Server;
using Microsoft.AspNet.Hosting.Startup;
using Microsoft.Framework.ConfigurationModel;
using Microsoft.Framework.DependencyInjection;
namespace Microsoft.AspNet.Hosting
{
public class HostingContext
{
public IApplicationLifetime ApplicationLifetime { get; set; }
public IConfiguration Configuration { get; set; }
public IApplicationBuilder Builder { get; set; }
public string ApplicationName { get; set; }
public string WebRootPath { get; set; }
public string EnvironmentName { get; set; }
public Action<IApplicationBuilder> ApplicationStartup { get; set; }
public StartupMethods StartupMethods { get; set; }
public RequestDelegate ApplicationDelegate { get; set; }
public IServiceCollection Services { get; } = new ServiceCollection();
// Result of ConfigureServices
public IServiceProvider ApplicationServices { get; set; }
public string ServerFactoryLocation { get; set; }
public IServerFactory ServerFactory { get; set; }
public IServerInformation Server { get; set; }

View File

@ -9,51 +9,116 @@ using Microsoft.AspNet.Hosting.Builder;
using Microsoft.AspNet.Hosting.Internal;
using Microsoft.AspNet.Hosting.Server;
using Microsoft.AspNet.Hosting.Startup;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Runtime;
using Microsoft.Framework.Runtime.Infrastructure;
namespace Microsoft.AspNet.Hosting
{
public class HostingEngine : IHostingEngine
public class HostingEngine
{
private readonly IServerLoader _serverManager;
private readonly IStartupLoader _startupLoader;
private readonly IApplicationBuilderFactory _builderFactory;
private readonly IHttpContextFactory _httpContextFactory;
private readonly IHttpContextAccessor _contextAccessor;
private const string EnvironmentKey = "ASPNET_ENV";
public HostingEngine(
IServerLoader serverManager,
IStartupLoader startupLoader,
IApplicationBuilderFactory builderFactory,
IHttpContextFactory httpContextFactory,
IHttpContextAccessor contextAccessor)
private readonly IServiceProvider _fallbackServices;
private readonly ApplicationLifetime _appLifetime;
private readonly IApplicationEnvironment _applicationEnvironment;
private readonly HostingEnvironment _hostingEnvironment;
private IServerLoader _serverLoader;
private IApplicationBuilderFactory _builderFactory;
public HostingEngine() : this(fallbackServices: null) { }
public HostingEngine(IServiceProvider fallbackServices)
{
_serverManager = serverManager;
_startupLoader = startupLoader;
_builderFactory = builderFactory;
_httpContextFactory = httpContextFactory;
_contextAccessor = contextAccessor;
_fallbackServices = fallbackServices ?? CallContextServiceLocator.Locator.ServiceProvider;
_appLifetime = new ApplicationLifetime();
_applicationEnvironment = _fallbackServices.GetRequiredService<IApplicationEnvironment>();
_hostingEnvironment = new HostingEnvironment(_applicationEnvironment);
_fallbackServices = new WrappingServiceProvider(_fallbackServices, _hostingEnvironment, _appLifetime);
}
public IDisposable Start(HostingContext context)
{
EnsureContextDefaults(context);
EnsureApplicationServices(context);
EnsureBuilder(context);
EnsureServerFactory(context);
InitalizeServerFactory(context);
EnsureApplicationDelegate(context);
var applicationLifetime = (ApplicationLifetime)context.ApplicationLifetime;
var pipeline = new PipelineInstance(_httpContextFactory, context.ApplicationDelegate, _contextAccessor);
var server = context.ServerFactory.Start(context.Server, pipeline.Invoke);
var contextFactory = context.ApplicationServices.GetRequiredService<IHttpContextFactory>();
var contextAccessor = context.ApplicationServices.GetRequiredService<IHttpContextAccessor>();
var server = context.ServerFactory.Start(context.Server,
features =>
{
var httpContext = contextFactory.CreateHttpContext(features);
contextAccessor.HttpContext = httpContext;
return context.ApplicationDelegate(httpContext);
});
return new Disposable(() =>
{
applicationLifetime.NotifyStopping();
_appLifetime.NotifyStopping();
server.Dispose();
pipeline.Dispose();
applicationLifetime.NotifyStopped();
_appLifetime.NotifyStopped();
});
}
private void EnsureContextDefaults(HostingContext context)
{
if (context.ApplicationName == null)
{
context.ApplicationName = _applicationEnvironment.ApplicationName;
}
if (context.EnvironmentName == null)
{
context.EnvironmentName = context.Configuration?.Get(EnvironmentKey) ?? HostingEnvironment.DefaultEnvironmentName;
}
_hostingEnvironment.EnvironmentName = context.EnvironmentName;
if (context.WebRootPath != null)
{
_hostingEnvironment.WebRootPath = context.WebRootPath;
}
}
private void EnsureApplicationServices(HostingContext context)
{
if (context.ApplicationServices != null)
{
return;
}
EnsureStartupMethods(context);
context.ApplicationServices = context.StartupMethods.ConfigureServicesDelegate(CreateHostingServices(context));
}
private void EnsureStartupMethods(HostingContext context)
{
if (context.StartupMethods != null)
{
return;
}
var diagnosticMessages = new List<string>();
context.StartupMethods = ApplicationStartup.LoadStartupMethods(
_fallbackServices,
context.ApplicationName,
context.EnvironmentName,
diagnosticMessages);
if (context.StartupMethods == null)
{
throw new ArgumentException(
diagnosticMessages.Aggregate("Failed to find an entry point for the web application.", (a, b) => a + "\r\n" + b),
nameof(context));
}
}
private void EnsureBuilder(HostingContext context)
{
if (context.Builder != null)
@ -61,7 +126,13 @@ namespace Microsoft.AspNet.Hosting
return;
}
if (_builderFactory == null)
{
_builderFactory = context.ApplicationServices.GetRequiredService<IApplicationBuilderFactory>();
}
context.Builder = _builderFactory.CreateBuilder();
context.Builder.ApplicationServices = context.ApplicationServices;
}
private void EnsureServerFactory(HostingContext context)
@ -71,7 +142,12 @@ namespace Microsoft.AspNet.Hosting
return;
}
context.ServerFactory = _serverManager.LoadServerFactory(context.ServerFactoryLocation);
if (_serverLoader == null)
{
_serverLoader = context.ApplicationServices.GetRequiredService<IServerLoader>();
}
context.ServerFactory = _serverLoader.LoadServerFactory(context.ServerFactoryLocation);
}
private void InitalizeServerFactory(HostingContext context)
@ -87,6 +163,32 @@ namespace Microsoft.AspNet.Hosting
}
}
private IServiceCollection CreateHostingServices(HostingContext context)
{
var services = Import(_fallbackServices);
services.TryAdd(ServiceDescriptor.Transient<IServerLoader, ServerLoader>());
services.TryAdd(ServiceDescriptor.Transient<IApplicationBuilderFactory, ApplicationBuilderFactory>());
services.TryAdd(ServiceDescriptor.Transient<IHttpContextFactory, HttpContextFactory>());
// TODO: Do we expect this to be provide by the runtime eventually?
services.AddLogging();
services.TryAdd(ServiceDescriptor.Singleton<IHttpContextAccessor, HttpContextAccessor>());
// Apply user services
services.Add(context.Services);
// Jamming in app lifetime and hosting env since these must not be replaceable
services.AddInstance<IApplicationLifetime>(_appLifetime);
services.AddInstance<IHostingEnvironment>(_hostingEnvironment);
// Conjure up a RequestServices
services.AddTransient<IStartupFilter, AutoRequestServicesStartupFilter>();
return services;
}
private void EnsureApplicationDelegate(HostingContext context)
{
if (context.ApplicationDelegate != null)
@ -94,30 +196,59 @@ namespace Microsoft.AspNet.Hosting
return;
}
EnsureApplicationStartup(context);
// REVIEW: should we call EnsureApplicationServices?
var startupFilters = context.ApplicationServices.GetService<IEnumerable<IStartupFilter>>();
var configure = context.StartupMethods.ConfigureDelegate;
foreach (var filter in startupFilters)
{
configure = filter.Configure(context.Builder, configure);
}
configure(context.Builder);
context.ApplicationStartup.Invoke(context.Builder);
context.ApplicationDelegate = context.Builder.Build();
}
private void EnsureApplicationStartup(HostingContext context)
private static IServiceCollection Import(IServiceProvider fallbackProvider)
{
if (context.ApplicationStartup != null)
var services = new ServiceCollection();
var manifest = fallbackProvider.GetRequiredService<IServiceManifest>();
foreach (var service in manifest.Services)
{
return;
services.AddTransient(service, sp => fallbackProvider.GetService(service));
}
var diagnosticMessages = new List<string>();
context.ApplicationStartup = _startupLoader.LoadStartup(
context.ApplicationName,
context.EnvironmentName,
diagnosticMessages);
return services;
}
if (context.ApplicationStartup == null)
private class WrappingServiceProvider : IServiceProvider
{
private readonly IServiceProvider _sp;
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IApplicationLifetime _applicationLifetime;
public WrappingServiceProvider(IServiceProvider sp,
IHostingEnvironment hostingEnvironment,
IApplicationLifetime applicationLifetime)
{
throw new ArgumentException(
diagnosticMessages.Aggregate("Failed to find an entry point for the web application.", (a, b) => a + "\r\n" + b),
nameof(context));
_sp = sp;
_hostingEnvironment = hostingEnvironment;
_applicationLifetime = applicationLifetime;
}
public object GetService(Type serviceType)
{
if (serviceType == typeof(IHostingEnvironment))
{
return _hostingEnvironment;
}
if (serviceType == typeof(IApplicationLifetime))
{
return _applicationLifetime;
}
return _sp.GetService(serviceType);
}
}

View File

@ -10,22 +10,18 @@ namespace Microsoft.AspNet.Hosting
{
public class HostingEnvironment : IHostingEnvironment
{
private const string DefaultEnvironmentName = "Development";
internal const string DefaultEnvironmentName = "Development";
public HostingEnvironment(IApplicationEnvironment appEnvironment, IEnumerable<IConfigureHostingEnvironment> configures)
public HostingEnvironment(IApplicationEnvironment appEnvironment)
{
EnvironmentName = DefaultEnvironmentName;
WebRootPath = HostingUtilities.GetWebRoot(appEnvironment.ApplicationBasePath);
WebRootFileProvider = new PhysicalFileProvider(WebRootPath);
foreach (var configure in configures)
{
configure.Configure(this);
}
}
public string EnvironmentName { get; set; }
public string WebRootPath { get; private set; }
public string WebRootPath { get; set; }
public IFileProvider WebRootFileProvider { get; private set; }
}

View File

@ -1,89 +0,0 @@
// 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 System.Collections.Generic;
using System.Linq;
using Microsoft.Framework.ConfigurationModel;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Logging;
using Microsoft.Framework.Runtime;
using Microsoft.Framework.Runtime.Infrastructure;
namespace Microsoft.AspNet.Hosting
{
public static class HostingServices
{
private static IServiceCollection Import(IServiceProvider fallbackProvider, Action<IServiceCollection> configureHostServices)
{
var services = new ServiceCollection();
var manifest = fallbackProvider.GetRequiredService<IServiceManifest>();
foreach (var service in manifest.Services)
{
services.AddTransient(service, sp => fallbackProvider.GetService(service));
}
if (configureHostServices != null)
{
configureHostServices(services);
}
services.AddSingleton<IServiceManifest>(sp => new HostingManifest(services));
return services;
}
public static IServiceCollection Create()
{
return Create(CallContextServiceLocator.Locator.ServiceProvider, configureHostServices: null, configuration: null);
}
public static IServiceCollection Create(IServiceProvider fallbackServices)
{
return Create(fallbackServices, configureHostServices: null, configuration: null);
}
public static IServiceCollection Create(Action<IServiceCollection> configureHostServices)
{
return Create(CallContextServiceLocator.Locator.ServiceProvider, configureHostServices, configuration: null);
}
public static IServiceCollection Create(IServiceProvider fallbackServices, Action<IServiceCollection> configureHostServices)
{
return Create(fallbackServices, configureHostServices, configuration: null);
}
public static IServiceCollection Create(Action<IServiceCollection> configureHostServices, IConfiguration configuration)
{
return Create(CallContextServiceLocator.Locator.ServiceProvider, configureHostServices, configuration);
}
public static IServiceCollection Create(IServiceProvider fallbackServices, IConfiguration configuration)
{
return Create(CallContextServiceLocator.Locator.ServiceProvider, configureHostServices: null, configuration: configuration);
}
public static IServiceCollection Create(IServiceProvider fallbackServices, Action<IServiceCollection> configureHostServices, IConfiguration configuration)
{
var services = Import(fallbackServices, configureHostServices);
services.AddHosting(configuration);
return services;
}
// Manifest exposes the fallback manifest in addition to ITypeActivator, IHostingEnvironment, and ILoggerFactory
private class HostingManifest : IServiceManifest
{
public HostingManifest(IServiceCollection hostServices)
{
Services = new Type[] {
typeof(IHostingEnvironment),
typeof(ILoggerFactory),
typeof(IHttpContextAccessor),
typeof(IApplicationLifetime)
}.Concat(hostServices.Select(s => s.ServiceType)).Distinct();
}
public IEnumerable<Type> Services { get; private set; }
}
}
}

View File

@ -1,42 +0,0 @@
// 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.Hosting;
using Microsoft.AspNet.Hosting.Builder;
using Microsoft.AspNet.Hosting.Server;
using Microsoft.AspNet.Hosting.Startup;
using Microsoft.Framework.ConfigurationModel;
namespace Microsoft.Framework.DependencyInjection
{
public static class HostingServicesExtensions
{
public static IServiceCollection AddHosting(this IServiceCollection services)
{
return services.AddHosting(configuration: null);
}
public static IServiceCollection AddHosting(this IServiceCollection services, IConfiguration configuration)
{
services.TryAdd(ServiceDescriptor.Transient<IHostingEngine, HostingEngine>());
services.TryAdd(ServiceDescriptor.Transient<IServerLoader, ServerLoader>());
services.TryAdd(ServiceDescriptor.Transient<IStartupLoader, StartupLoader>());
services.TryAdd(ServiceDescriptor.Transient<IApplicationBuilderFactory, ApplicationBuilderFactory>());
services.TryAdd(ServiceDescriptor.Transient<IHttpContextFactory, HttpContextFactory>());
services.TryAdd(ServiceDescriptor.Instance<IApplicationLifetime>(new ApplicationLifetime()));
// TODO: Do we expect this to be provide by the runtime eventually?
services.AddLogging();
services.TryAdd(ServiceDescriptor.Singleton<IHostingEnvironment, HostingEnvironment>());
services.TryAdd(ServiceDescriptor.Singleton<IHttpContextAccessor, HttpContextAccessor>());
// REVIEW: don't try add because we pull out IEnumerable<IConfigureHostingEnvironment>?
services.AddInstance<IConfigureHostingEnvironment>(new ConfigureHostingEnvironment(configuration));
return services;
}
}
}

View File

@ -1,12 +0,0 @@
// 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;
namespace Microsoft.AspNet.Hosting
{
public interface IHostingEngine
{
IDisposable Start(HostingContext context);
}
}

View File

@ -0,0 +1,21 @@
// 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.Builder;
using Microsoft.AspNet.Hosting.Startup;
namespace Microsoft.AspNet.Hosting.Internal
{
public class AutoRequestServicesStartupFilter : IStartupFilter
{
public Action<IApplicationBuilder> Configure(IApplicationBuilder app, Action<IApplicationBuilder> next)
{
return builder =>
{
app.UseMiddleware<RequestServicesContainerMiddleware>();
next(builder);
};
}
}
}

View File

@ -1,37 +0,0 @@
// 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 System.Threading.Tasks;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.FeatureModel;
using Microsoft.AspNet.Hosting.Builder;
namespace Microsoft.AspNet.Hosting.Internal
{
public class PipelineInstance : IDisposable
{
private readonly IHttpContextFactory _httpContextFactory;
private readonly RequestDelegate _requestDelegate;
private readonly IHttpContextAccessor _contextAccessor;
public PipelineInstance(IHttpContextFactory httpContextFactory, RequestDelegate requestDelegate, IHttpContextAccessor contextAccessor)
{
_httpContextFactory = httpContextFactory;
_requestDelegate = requestDelegate;
_contextAccessor = contextAccessor;
}
public Task Invoke(IFeatureCollection featureCollection)
{
var httpContext = _httpContextFactory.CreateHttpContext(featureCollection);
_contextAccessor.HttpContext = httpContext;
return _requestDelegate(httpContext);
}
public void Dispose()
{
// TODO: application notification of disposal
}
}
}

View File

@ -5,7 +5,7 @@ using System;
using Microsoft.AspNet.Http;
using Microsoft.Framework.DependencyInjection;
namespace Microsoft.AspNet.RequestContainer
namespace Microsoft.AspNet.Hosting.Internal
{
public class RequestServicesContainer : IDisposable
{

View File

@ -6,14 +6,14 @@ using System.Threading.Tasks;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http;
namespace Microsoft.AspNet.RequestContainer
namespace Microsoft.AspNet.Hosting.Internal
{
public class ContainerMiddleware
public class RequestServicesContainerMiddleware
{
private readonly RequestDelegate _next;
private readonly IServiceProvider _services;
public ContainerMiddleware(RequestDelegate next, IServiceProvider services)
public RequestServicesContainerMiddleware(RequestDelegate next, IServiceProvider services)
{
_services = services;
_next = next;
@ -21,11 +21,6 @@ namespace Microsoft.AspNet.RequestContainer
public async Task Invoke(HttpContext httpContext)
{
if (httpContext.RequestServices != null)
{
throw new Exception("TODO: nested request container scope? this is probably a mistake on your part?");
}
using (var container = RequestServicesContainer.EnsureRequestServices(httpContext, _services))
{
await _next.Invoke(httpContext);

View File

@ -33,29 +33,19 @@ namespace Microsoft.AspNet.Hosting
config.AddEnvironmentVariables();
config.AddCommandLine(args);
var services = HostingServices.Create(_serviceProvider, config)
.BuildServiceProvider();
var appEnv = services.GetRequiredService<IApplicationEnvironment>();
var hostingEnv = services.GetRequiredService<IHostingEnvironment>();
var applicationLifetime = services.GetRequiredService<IApplicationLifetime>();
var context = new HostingContext()
{
ApplicationLifetime = applicationLifetime,
Configuration = config,
ServerFactoryLocation = config.Get("server"), // TODO: Key names
ApplicationName = config.Get("app") // TODO: Key names
?? appEnv.ApplicationName,
EnvironmentName = hostingEnv.EnvironmentName,
ServerFactoryLocation = config.Get("server"),
ApplicationName = config.Get("app")
};
var engine = services.GetRequiredService<IHostingEngine>();
var loggerFactory = services.GetRequiredService<ILoggerFactory>();
var appShutdownService = _serviceProvider.GetRequiredService<IApplicationShutdown>();
var shutdownHandle = new ManualResetEvent(false);
var engine = new HostingEngine(_serviceProvider);
var serverShutdown = engine.Start(context);
var loggerFactory = context.ApplicationServices.GetRequiredService<ILoggerFactory>();
var appShutdownService = context.ApplicationServices.GetRequiredService<IApplicationShutdown>();
var shutdownHandle = new ManualResetEvent(false);
appShutdownService.ShutdownRequested.Register(() =>
{

View File

@ -0,0 +1,125 @@
// 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 System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using Microsoft.Framework.DependencyInjection;
namespace Microsoft.AspNet.Hosting.Startup
{
public static class ApplicationStartup
{
internal static ConfigureServicesDelegate DefaultBuildServiceProvider = s => s.BuildServiceProvider();
public static StartupMethods LoadStartupMethods(
IServiceProvider services,
string applicationName,
string environmentName,
IList<string> diagnosticMessages)
{
if (string.IsNullOrEmpty(applicationName))
{
throw new ArgumentException("Value cannot be null or empty.", "applicationName");
}
var assembly = Assembly.Load(new AssemblyName(applicationName));
if (assembly == null)
{
throw new InvalidOperationException(String.Format("The assembly '{0}' failed to load.", applicationName));
}
var startupNameWithEnv = "Startup" + environmentName;
var startupNameWithoutEnv = "Startup";
// Check the most likely places first
var type =
assembly.GetType(startupNameWithEnv) ??
assembly.GetType(applicationName + "." + startupNameWithEnv) ??
assembly.GetType(startupNameWithoutEnv) ??
assembly.GetType(applicationName + "." + startupNameWithoutEnv);
if (type == null)
{
// Full scan
var definedTypes = assembly.DefinedTypes.ToList();
var startupType1 = definedTypes.Where(info => info.Name.Equals(startupNameWithEnv, StringComparison.Ordinal));
var startupType2 = definedTypes.Where(info => info.Name.Equals(startupNameWithoutEnv, StringComparison.Ordinal));
var typeInfo = startupType1.Concat(startupType2).FirstOrDefault();
if (typeInfo != null)
{
type = typeInfo.AsType();
}
}
if (type == null)
{
throw new InvalidOperationException(String.Format("A type named '{0}' or '{1}' could not be found in assembly '{2}'.",
startupNameWithEnv,
startupNameWithoutEnv,
applicationName));
}
var configureMethod = FindConfigureDelegate(type, environmentName);
var servicesMethod = FindConfigureServicesDelegate(type, environmentName);
object instance = null;
if (!configureMethod.MethodInfo.IsStatic || (servicesMethod != null && !servicesMethod.MethodInfo.IsStatic))
{
instance = ActivatorUtilities.GetServiceOrCreateInstance(services, type);
}
return new StartupMethods(configureMethod.Build(instance), servicesMethod?.Build(instance));
}
public static ConfigureBuilder FindConfigureDelegate(Type startupType, string environmentName)
{
var configureMethod = FindMethod(startupType, "Configure{0}", environmentName, typeof(void), required: true);
return new ConfigureBuilder(configureMethod);
}
public static ConfigureServicesBuilder FindConfigureServicesDelegate(Type startupType, string environmentName)
{
var servicesMethod = FindMethod(startupType, "Configure{0}Services", environmentName, typeof(IServiceProvider), required: false)
?? FindMethod(startupType, "Configure{0}Services", environmentName, typeof(void), required: false);
return servicesMethod == null ? null : new ConfigureServicesBuilder(servicesMethod);
}
private static MethodInfo FindMethod(Type startupType, string methodName, string environmentName, Type returnType = null, bool required = true)
{
var methodNameWithEnv = string.Format(CultureInfo.InvariantCulture, methodName, environmentName);
var methodNameWithNoEnv = string.Format(CultureInfo.InvariantCulture, methodName, "");
var methodInfo = startupType.GetMethod(methodNameWithEnv, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
?? startupType.GetMethod(methodNameWithNoEnv, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
if (methodInfo == null)
{
if (required)
{
throw new InvalidOperationException(string.Format("A method named '{0}' or '{1}' in the type '{2}' could not be found.",
methodNameWithEnv,
methodNameWithNoEnv,
startupType.FullName));
}
return null;
}
if (returnType != null && methodInfo.ReturnType != returnType)
{
if (required)
{
throw new InvalidOperationException(string.Format("The '{0}' method in the type '{1}' must have a return type of '{2}'.",
methodInfo.Name,
startupType.FullName,
returnType.Name));
}
return null;
}
return methodInfo;
}
}
}

View File

@ -0,0 +1,60 @@
// 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 System.Reflection;
using Microsoft.AspNet.Builder;
using Microsoft.Framework.DependencyInjection;
namespace Microsoft.AspNet.Hosting.Startup
{
// TODO: replace all Action<IApplicationBuilder> eventually with this
public delegate void ConfigureDelegate(IApplicationBuilder builder);
public class ConfigureBuilder
{
public ConfigureBuilder(MethodInfo configure)
{
MethodInfo = configure;
}
public MethodInfo MethodInfo { get; }
public Action<IApplicationBuilder> Build(object instance)
{
return builder => Invoke(instance, builder);
}
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)
{
var parameterInfo = parameterInfos[index];
if (parameterInfo.ParameterType == typeof(IApplicationBuilder))
{
parameters[index] = builder;
}
else
{
try
{
parameters[index] = serviceProvider.GetRequiredService(parameterInfo.ParameterType);
}
catch (Exception)
{
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));
}
}
}
MethodInfo.Invoke(instance, parameters);
}
}
}

View File

@ -0,0 +1,43 @@
// 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 System.Reflection;
using Microsoft.Framework.DependencyInjection;
namespace Microsoft.AspNet.Hosting.Startup
{
public delegate IServiceProvider ConfigureServicesDelegate(IServiceCollection services);
public class ConfigureServicesBuilder
{
public ConfigureServicesBuilder(MethodInfo configureServices)
{
MethodInfo = configureServices;
}
public MethodInfo MethodInfo { get; }
public ConfigureServicesDelegate Build(object instance)
{
return services => Invoke(instance, services);
}
private IServiceProvider Invoke(object instance, IServiceCollection exportServices)
{
var parameterInfos = MethodInfo.GetParameters();
var parameters = new object[parameterInfos.Length];
for (var index = 0; index != parameterInfos.Length; ++index)
{
var parameterInfo = parameterInfos[index];
if (exportServices != null && parameterInfo.ParameterType == typeof(IServiceCollection))
{
parameters[index] = exportServices;
}
}
// REVIEW: We null ref if exportServices is null, cuz it should not be null
return MethodInfo.Invoke(instance, parameters) as IServiceProvider ?? exportServices.BuildServiceProvider();
}
}
}

View File

@ -2,16 +2,13 @@
// 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.Builder;
namespace Microsoft.AspNet.Hosting.Startup
{
public interface IStartupLoader
public interface IStartupFilter
{
Action<IApplicationBuilder> LoadStartup(
string applicationName,
string environmentName,
IList<string> diagnosticMessages);
// TODO: replace with ConfigureDelegate?
Action<IApplicationBuilder> Configure(IApplicationBuilder app, Action<IApplicationBuilder> next);
}
}

View File

@ -1,174 +0,0 @@
// 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 System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using Microsoft.AspNet.Builder;
using Microsoft.Framework.DependencyInjection;
namespace Microsoft.AspNet.Hosting.Startup
{
public class StartupLoader : IStartupLoader
{
private readonly IServiceProvider _services;
public StartupLoader(IServiceProvider services)
{
_services = services;
}
private MethodInfo FindMethod(Type startupType, string methodName, string environmentName, Type returnType = null, bool required = true)
{
var methodNameWithEnv = string.Format(CultureInfo.InvariantCulture, methodName, environmentName);
var methodNameWithNoEnv = string.Format(CultureInfo.InvariantCulture, methodName, "");
var methodInfo = startupType.GetMethod(methodNameWithEnv, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
?? startupType.GetMethod(methodNameWithNoEnv, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
if (methodInfo == null)
{
if (required)
{
throw new Exception(string.Format("A method named '{0}' or '{1}' in the type '{2}' could not be found.",
methodNameWithEnv,
methodNameWithNoEnv,
startupType.FullName));
}
return null;
}
if (returnType != null && methodInfo.ReturnType != returnType)
{
if (required)
{
throw new Exception(string.Format("The '{0}' method in the type '{1}' must have a return type of '{2}'.",
methodInfo.Name,
startupType.FullName,
returnType.Name));
}
return null;
}
return methodInfo;
}
private object Invoke(MethodInfo methodInfo, object instance, IApplicationBuilder builder, IServiceCollection services = null)
{
var serviceProvider = builder.ApplicationServices ?? _services;
var parameterInfos = methodInfo.GetParameters();
var parameters = new object[parameterInfos.Length];
for (var index = 0; index != parameterInfos.Length; ++index)
{
var parameterInfo = parameterInfos[index];
if (parameterInfo.ParameterType == typeof(IApplicationBuilder))
{
parameters[index] = builder;
}
else if (services != null && parameterInfo.ParameterType == typeof(IServiceCollection))
{
parameters[index] = services;
}
else
{
try
{
parameters[index] = serviceProvider.GetRequiredService(parameterInfo.ParameterType);
}
catch (Exception)
{
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));
}
}
}
return methodInfo.Invoke(instance, parameters);
}
public Action<IApplicationBuilder> LoadStartup(
string applicationName,
string environmentName,
IList<string> diagnosticMessages)
{
if (string.IsNullOrEmpty(applicationName))
{
throw new ArgumentException("Value cannot be null or empty.", "applicationName");
}
var assembly = Assembly.Load(new AssemblyName(applicationName));
if (assembly == null)
{
throw new Exception(String.Format("The assembly '{0}' failed to load.", applicationName));
}
var startupNameWithEnv = "Startup" + environmentName;
var startupNameWithoutEnv = "Startup";
// Check the most likely places first
var type =
assembly.GetType(startupNameWithEnv) ??
assembly.GetType(applicationName + "." + startupNameWithEnv) ??
assembly.GetType(startupNameWithoutEnv) ??
assembly.GetType(applicationName + "." + startupNameWithoutEnv);
if (type == null)
{
// Full scan
var definedTypes = assembly.DefinedTypes.ToList();
var startupType1 = definedTypes.Where(info => info.Name.Equals(startupNameWithEnv, StringComparison.Ordinal));
var startupType2 = definedTypes.Where(info => info.Name.Equals(startupNameWithoutEnv, StringComparison.Ordinal));
var typeInfo = startupType1.Concat(startupType2).FirstOrDefault();
if (typeInfo != null)
{
type = typeInfo.AsType();
}
}
if (type == null)
{
throw new Exception(String.Format("A type named '{0}' or '{1}' could not be found in assembly '{2}'.",
startupNameWithEnv,
startupNameWithoutEnv,
applicationName));
}
var configureMethod = FindMethod(type, "Configure{0}", environmentName, typeof(void), required: true);
var servicesMethod = FindMethod(type, "Configure{0}Services", environmentName, typeof(IServiceProvider), required: false)
?? FindMethod(type, "Configure{0}Services", environmentName, typeof(void), required: false);
object instance = null;
if (!configureMethod.IsStatic || (servicesMethod != null && !servicesMethod.IsStatic))
{
instance = ActivatorUtilities.GetServiceOrCreateInstance(_services, type);
}
return builder =>
{
if (servicesMethod != null)
{
var services = HostingServices.Create(builder.ApplicationServices);
if (servicesMethod.ReturnType == typeof(IServiceProvider))
{
// IServiceProvider ConfigureServices(IServiceCollection)
builder.ApplicationServices = (Invoke(servicesMethod, instance, builder, services) as IServiceProvider)
?? builder.ApplicationServices;
}
else
{
// void ConfigureServices(IServiceCollection)
Invoke(servicesMethod, instance, builder, services);
if (builder != null)
{
builder.ApplicationServices = services.BuildServiceProvider();
}
}
}
Invoke(configureMethod, instance, builder);
};
}
}
}

View File

@ -0,0 +1,22 @@
// 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.Builder;
namespace Microsoft.AspNet.Hosting.Startup
{
public class StartupMethods
{
// TODO: switch to ConfigureDelegate eventually
public StartupMethods(Action<IApplicationBuilder> configure, ConfigureServicesDelegate configureServices)
{
ConfigureDelegate = configure;
ConfigureServicesDelegate = configureServices ?? ApplicationStartup.DefaultBuildServiceProvider;
}
public ConfigureServicesDelegate ConfigureServicesDelegate { get; }
public Action<IApplicationBuilder> ConfigureDelegate { get; }
}
}

View File

@ -6,6 +6,7 @@
"Microsoft.Framework.Runtime.Interfaces": "1.0.0-*",
"Microsoft.AspNet.FileProviders": "1.0.0-*",
"Microsoft.AspNet.Http.Core": "1.0.0-*",
"Microsoft.AspNet.Http.Extensions": "1.0.0-*",
"Microsoft.Framework.Logging": "1.0.0-*",
"Microsoft.Framework.DependencyInjection": "1.0.0-*",
"Newtonsoft.Json": "6.0.6"

View File

@ -1,55 +0,0 @@
// 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 System.Collections.Generic;
using Microsoft.AspNet.RequestContainer;
using Microsoft.AspNet.Hosting;
using Microsoft.Framework.DependencyInjection;
namespace Microsoft.AspNet.Builder
{
public static class ContainerExtensions
{
public static IApplicationBuilder UseRequestServices(this IApplicationBuilder builder)
{
return builder.UseMiddleware<ContainerMiddleware>();
}
// Review: what do we use these for?
public static IApplicationBuilder UseRequestServices(this IApplicationBuilder builder, IServiceProvider applicationServices)
{
// REVIEW: should this be doing fallback?
builder.ApplicationServices = applicationServices;
return builder.UseMiddleware<ContainerMiddleware>();
}
// Note: Manifests are lost after UseServices, services are flattened into ApplicationServices
public static IApplicationBuilder UseServices(this IApplicationBuilder builder, IServiceCollection applicationServices)
{
return builder.UseServices(services => services.Add(applicationServices));
}
public static IApplicationBuilder UseServices(this IApplicationBuilder builder, Action<IServiceCollection> configureServices)
{
return builder.UseServices(serviceCollection =>
{
configureServices(serviceCollection);
return serviceCollection.BuildServiceProvider();
});
}
public static IApplicationBuilder UseServices(this IApplicationBuilder builder, Func<IServiceCollection, IServiceProvider> configureServices)
{
// Import services from hosting/DNX as fallback
var serviceCollection = HostingServices.Create(builder.ApplicationServices);
builder.ApplicationServices = configureServices(serviceCollection);
return builder.UseMiddleware<ContainerMiddleware>();
}
}
}

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>374a5b0c-3e93-4a23-a4a0-ee2ab6df7814</ProjectGuid>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@ -1,17 +0,0 @@
{
"version": "1.0.0-*",
"description": "ASP.NET 5 enables per-request scoping of services.",
"dependencies": {
"Microsoft.AspNet.Http.Extensions": "1.0.0-*",
"Microsoft.AspNet.Hosting": "1.0.0-*",
"Microsoft.Framework.OptionsModel": "1.0.0-*"
},
"frameworks": {
"dnx451": {},
"dnxcore50": {
"dependencies": {
"System.Threading": "4.0.10-beta-*"
}
},
}
}

View File

@ -8,10 +8,10 @@ using Microsoft.AspNet.Builder;
using Microsoft.AspNet.FeatureModel;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Hosting.Server;
using Microsoft.AspNet.Hosting.Startup;
using Microsoft.AspNet.Http;
using Microsoft.Framework.ConfigurationModel;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Runtime;
using Microsoft.Framework.Runtime.Infrastructure;
namespace Microsoft.AspNet.TestHost
@ -25,46 +25,63 @@ namespace Microsoft.AspNet.TestHost
private IDisposable _appInstance;
private bool _disposed = false;
public TestServer(IConfiguration config, IServiceProvider serviceProvider, Action<IApplicationBuilder> appStartup)
// REVIEW: we can configure services via AppStartup or via hostContext.Services
public TestServer(IConfiguration config, IServiceProvider serviceProvider, Action<IApplicationBuilder> configureApp, ConfigureServicesDelegate configureServices)
{
var appEnv = serviceProvider.GetRequiredService<IApplicationEnvironment>();
var applicationLifetime = serviceProvider.GetRequiredService<IApplicationLifetime>();
HostingContext hostContext = new HostingContext()
var hostContext = new HostingContext()
{
ApplicationName = appEnv.ApplicationName,
ApplicationLifetime = applicationLifetime,
ApplicationName = "Test App",
Configuration = config,
ServerFactory = this,
ApplicationStartup = appStartup
StartupMethods = new StartupMethods(configureApp, configureServices)
};
var engine = serviceProvider.GetRequiredService<IHostingEngine>();
_appInstance = engine.Start(hostContext);
_appInstance = new HostingEngine(serviceProvider).Start(hostContext);
}
public Uri BaseAddress { get; set; } = new Uri("http://localhost/");
public static TestServer Create(Action<IApplicationBuilder> app)
public static TestServer Create(Action<IApplicationBuilder> configureApp)
{
return Create(CallContextServiceLocator.Locator.ServiceProvider, app, configureHostServices: null);
return Create(CallContextServiceLocator.Locator.ServiceProvider, configureApp, configureServices: null);
}
public static TestServer Create(Action<IApplicationBuilder> app, Action<IServiceCollection> configureHostServices)
public static TestServer Create(Action<IApplicationBuilder> configureApp, Action<IServiceCollection> configureServices)
{
return Create(CallContextServiceLocator.Locator.ServiceProvider, app, configureHostServices);
return Create(CallContextServiceLocator.Locator.ServiceProvider, configureApp,
sc =>
{
if (configureServices != null)
{
configureServices(sc);
}
return sc.BuildServiceProvider();
});
}
public static TestServer Create(IServiceProvider serviceProvider, Action<IApplicationBuilder> app)
public static TestServer Create(IServiceProvider serviceProvider, Action<IApplicationBuilder> configureApp)
{
return Create(serviceProvider, app, configureHostServices: null);
return Create(serviceProvider, configureApp, configureServices: null);
}
public static TestServer Create(IServiceProvider serviceProvider, Action<IApplicationBuilder> app, Action<IServiceCollection> configureHostServices)
public static TestServer Create(IServiceProvider serviceProvider, Action<IApplicationBuilder> configureApp, Action<IServiceCollection> configureServices)
{
var appServices = HostingServices.Create(serviceProvider, configureHostServices).BuildServiceProvider();
return Create(serviceProvider, configureApp,
sc =>
{
if (configureServices != null)
{
configureServices(sc);
}
return sc.BuildServiceProvider();
});
}
public static TestServer Create(IServiceProvider serviceProvider, Action<IApplicationBuilder> configureApp, ConfigureServicesDelegate configureServices)
{
// REVIEW: do we need an overload that takes Config for Create?
var config = new Configuration();
return new TestServer(config, appServices, app);
return new TestServer(config, serviceProvider, configureApp, configureServices);
}
public HttpMessageHandler CreateHandler()
@ -124,7 +141,7 @@ namespace Microsoft.AspNet.TestHost
{
public string Name
{
get { return TestServer.ServerName; }
get { return ServerName; }
}
}
}

View File

@ -1,30 +0,0 @@
// 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<FakeOptions>(o => o.Configured = true);
services.AddTransient<IFakeService, FakeService>();
}
public void Configure(IApplicationBuilder builder)
{
builder.UseServices(services =>
{
services.AddTransient<FakeService>();
services.Configure<FakeOptions>(o => o.Message = "Configured");
});
}
}
}

View File

@ -0,0 +1,16 @@
using System;
using Microsoft.AspNet.Builder;
using Microsoft.Framework.DependencyInjection;
namespace Microsoft.AspNet.Hosting.Fakes
{
public class StartupWithNullConfigureServices
{
public IServiceProvider ConfigureServices(IServiceCollection services)
{
return null;
}
public void Configure(IApplicationBuilder app) { }
}
}

View File

@ -18,32 +18,16 @@ namespace Microsoft.AspNet.Hosting
{
private readonly IList<StartInstance> _startInstances = new List<StartInstance>();
[Fact]
public void HostingEngineCanBeResolvedWithDefaultServices()
{
var services = HostingServices.Create().BuildServiceProvider();
var engine = services.GetRequiredService<IHostingEngine>();
Assert.NotNull(engine);
}
[Fact]
public void HostingEngineCanBeStarted()
{
var services = HostingServices.Create().BuildServiceProvider();
var engine = services.GetRequiredService<IHostingEngine>();
var applicationLifetime = services.GetRequiredService<IApplicationLifetime>();
var context = new HostingContext
{
ApplicationLifetime = applicationLifetime,
ServerFactory = this,
ApplicationName = "Microsoft.AspNet.Hosting.Tests"
};
var engineStart = engine.Start(context);
var engineStart = new HostingEngine().Start(context);
Assert.NotNull(engineStart);
Assert.Equal(1, _startInstances.Count);
@ -54,39 +38,97 @@ namespace Microsoft.AspNet.Hosting
Assert.Equal(1, _startInstances[0].DisposeCalls);
}
[Fact]
public void ApplicationNameDefaultsToApplicationEnvironmentName()
{
var context = new HostingContext
{
ServerFactory = this
};
var engine = new HostingEngine();
using (engine.Start(context))
{
Assert.Equal("Microsoft.AspNet.Hosting.Tests", context.ApplicationName);
}
}
[Fact]
public void EnvDefaultsToDevelopmentIfNoConfig()
{
var context = new HostingContext
{
ServerFactory = this
};
var engine = new HostingEngine();
using (engine.Start(context))
{
Assert.Equal("Development", context.EnvironmentName);
var env = context.ApplicationServices.GetRequiredService<IHostingEnvironment>();
Assert.Equal("Development", env.EnvironmentName);
}
}
[Fact]
public void EnvDefaultsToDevelopmentConfigValueIfSpecified()
{
var vals = new Dictionary<string, string>
{
{ "ASPNET_ENV", "Staging" }
};
var config = new Configuration()
.Add(new MemoryConfigurationSource(vals));
var context = new HostingContext
{
ServerFactory = this,
Configuration = config
};
var engine = new HostingEngine();
using (engine.Start(context))
{
Assert.Equal("Staging", context.EnvironmentName);
var env = context.ApplicationServices.GetRequiredService<IHostingEnvironment>();
Assert.Equal("Staging", env.EnvironmentName);
}
}
[Fact]
public void WebRootCanBeResolvedFromTheProjectJson()
{
var services = HostingServices.Create().BuildServiceProvider();
var env = services.GetRequiredService<IHostingEnvironment>();
var context = new HostingContext
{
ServerFactory = this
};
var engineStart = new HostingEngine().Start(context);
var env = context.ApplicationServices.GetRequiredService<IHostingEnvironment>();
Assert.Equal(Path.GetFullPath("testroot"), env.WebRootPath);
Assert.True(env.WebRootFileProvider.GetFileInfo("TextFile.txt").Exists);
}
[Fact]
public void Validate_Environment_Name()
{
var services = HostingServices.Create().BuildServiceProvider();
var env = services.GetRequiredService<IHostingEnvironment>();
Assert.Equal("Development", env.EnvironmentName);
var config = new Configuration()
.AddCommandLine(new string[] { "--ASPNET_ENV", "Overridden_Environment" });
services = HostingServices.Create(fallbackServices: null, configuration: config)
.BuildServiceProvider();
env = services.GetRequiredService<IHostingEnvironment>();
Assert.Equal("Overridden_Environment", env.EnvironmentName);
}
[Fact]
public void IsEnvironment_Extension_Is_Case_Insensitive()
{
var services = HostingServices.Create().BuildServiceProvider();
var env = services.GetRequiredService<IHostingEnvironment>();
Assert.True(env.IsEnvironment("Development"));
Assert.True(env.IsEnvironment("developMent"));
var context = new HostingContext
{
ServerFactory = this
};
var engine = new HostingEngine();
using (engine.Start(context))
{
var env = context.ApplicationServices.GetRequiredService<IHostingEnvironment>();
Assert.True(env.IsEnvironment("Development"));
Assert.True(env.IsEnvironment("developMent"));
}
}
public void Initialize(IApplicationBuilder builder)

View File

@ -1,210 +0,0 @@
// 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 System.Collections.Generic;
using Microsoft.AspNet.Hosting.Fakes;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Runtime;
using Xunit;
namespace Microsoft.AspNet.Hosting.Tests
{
public class HostingServicesFacts
{
[Fact]
public void CreateImportsServices()
{
// Arrange
var fallbackServices = new ServiceCollection();
fallbackServices.AddSingleton<IFakeSingletonService, FakeService>();
var instance = new FakeService();
var factoryInstance = new FakeFactoryService(instance);
fallbackServices.AddInstance<IFakeServiceInstance>(instance);
fallbackServices.AddTransient<IFakeService, FakeService>();
fallbackServices.AddSingleton<IFactoryService>(serviceProvider => factoryInstance);
fallbackServices.AddTransient<IFakeScopedService, FakeService>(); // Don't register in manifest
fallbackServices.AddInstance<IServiceManifest>(new ServiceManifest(
new Type[] {
typeof(IFakeServiceInstance),
typeof(IFakeService),
typeof(IFakeSingletonService),
typeof(IFactoryService),
typeof(INonexistentService)
}));
var services = HostingServices.Create(fallbackServices.BuildServiceProvider());
// Act
var provider = services.BuildServiceProvider();
var singleton = provider.GetRequiredService<IFakeSingletonService>();
var transient = provider.GetRequiredService<IFakeService>();
var factory = provider.GetRequiredService<IFactoryService>();
// Assert
Assert.Same(singleton, provider.GetRequiredService<IFakeSingletonService>());
Assert.NotSame(transient, provider.GetRequiredService<IFakeService>());
Assert.Same(instance, provider.GetRequiredService<IFakeServiceInstance>());
Assert.Same(factoryInstance, factory);
Assert.Same(factory.FakeService, instance);
Assert.Null(provider.GetService<INonexistentService>());
Assert.Null(provider.GetService<IFakeScopedService>()); // Make sure we don't leak non manifest services
}
[Fact]
public void CreateCanAddAdditionalServices()
{
// Arrange
var fallbackServices = new ServiceCollection();
fallbackServices.AddTransient<IFakeService, FakeService>();
fallbackServices.AddTransient<IFakeScopedService, FakeService>(); // Don't register in manifest
fallbackServices.AddInstance<IServiceManifest>(new ServiceManifest(
new Type[] {
typeof(IFakeService),
}));
var instance = new FakeService();
var factoryInstance = new FakeFactoryService(instance);
var services = HostingServices.Create(fallbackServices.BuildServiceProvider(),
additionalHostServices =>
{
additionalHostServices.AddSingleton<IFakeSingletonService, FakeService>();
additionalHostServices.AddInstance<IFakeServiceInstance>(instance);
additionalHostServices.AddSingleton<IFactoryService>(serviceProvider => factoryInstance);
});
// Act
var provider = services.BuildServiceProvider();
var singleton = provider.GetRequiredService<IFakeSingletonService>();
var transient = provider.GetRequiredService<IFakeService>();
var factory = provider.GetRequiredService<IFactoryService>();
var manifest = provider.GetRequiredService<IServiceManifest>();
// Assert
Assert.Same(singleton, provider.GetRequiredService<IFakeSingletonService>());
Assert.NotSame(transient, provider.GetRequiredService<IFakeService>());
Assert.Same(instance, provider.GetRequiredService<IFakeServiceInstance>());
Assert.Same(factoryInstance, factory);
Assert.Same(factory.FakeService, instance);
Assert.Null(provider.GetService<INonexistentService>());
Assert.Null(provider.GetService<IFakeScopedService>()); // Make sure we don't leak non manifest services
Assert.Contains(typeof(IFakeSingletonService), manifest.Services);
Assert.Contains(typeof(IFakeServiceInstance), manifest.Services);
Assert.Contains(typeof(IFactoryService), manifest.Services);
}
[Fact]
public void CreateAdditionalServicesOverridesFallback()
{
// Arrange
var fallbackServices = new ServiceCollection();
fallbackServices.AddTransient<IFakeService, FakeService>();
fallbackServices.AddInstance<IServiceManifest>(new ServiceManifest(
new Type[] {
typeof(IFakeService),
}));
var services = HostingServices.Create(fallbackServices.BuildServiceProvider(),
additionalHostServices => additionalHostServices.AddSingleton<IFakeService, FakeService>());
// Act
var provider = services.BuildServiceProvider();
var singleton = provider.GetRequiredService<IFakeService>();
// Assert
Assert.Same(singleton, provider.GetRequiredService<IFakeService>());
}
[Fact]
public void CreateAdditionalServices_IncludesServicesInManifest()
{
// Arrange
var fallbackServices = new ServiceCollection();
fallbackServices.AddTransient<IFakeService, FakeService>();
fallbackServices.AddInstance<IServiceManifest>(new ServiceManifest(
new Type[] {
typeof(IFakeService),
}));
var expectedInstance = new FakeService();
var services = HostingServices.Create(
fallbackServices.BuildServiceProvider(),
additionalHostServices => additionalHostServices.AddInstance<IFakeServiceInstance>(expectedInstance));
// Act
var provider = services.BuildServiceProvider();
var instance = provider.GetRequiredService<IFakeServiceInstance>();
var anotherInstance = provider.GetRequiredService<IFakeServiceInstance>();
var manifest = provider.GetRequiredService<IServiceManifest>();
// Assert
Assert.Same(expectedInstance, instance);
Assert.Same(expectedInstance, anotherInstance);
Assert.Contains(typeof(IFakeServiceInstance), manifest.Services);
}
[Fact]
public void CanHideImportedServices()
{
// Arrange
var fallbackServices = new ServiceCollection();
var fallbackInstance = new FakeService();
fallbackServices.AddInstance<IFakeService>(fallbackInstance);
fallbackServices.AddInstance<IServiceManifest>(new ServiceManifest(new Type[] { typeof(IFakeService) }));
var services = HostingServices.Create(fallbackServices.BuildServiceProvider());
var realInstance = new FakeService();
services.AddInstance<IFakeService>(realInstance);
// Act
var provider = services.BuildServiceProvider();
// Assert
Assert.Equal(realInstance, provider.GetRequiredService<IFakeService>());
}
[Fact]
public void CreateThrowsWithNoManifest()
{
// Arrange
var fallbackServices = new ServiceCollection();
fallbackServices.AddSingleton<IFakeSingletonService, FakeService>();
var instance = new FakeService();
fallbackServices.AddInstance<IFakeServiceInstance>(instance);
fallbackServices.AddTransient<IFakeService, FakeService>();
// Act
var exception = Assert.Throws<InvalidOperationException>(() => HostingServices.Create(fallbackServices.BuildServiceProvider()));
// Assert
Assert.Equal($"No service for type '{typeof(IServiceManifest).FullName}' has been registered.",
exception.Message);
}
private class ServiceManifest : IServiceManifest
{
public ServiceManifest(IEnumerable<Type> services)
{
Services = services;
}
public IEnumerable<Type> Services { get; private set; }
}
private class FakeFactoryService : IFactoryService
{
public FakeFactoryService(FakeService service)
{
FakeService = service;
}
public IFakeService FakeService { get; private set; }
public int Value { get; private set; }
}
}
}

View File

@ -12,7 +12,6 @@ using Xunit;
namespace Microsoft.AspNet.Hosting.Tests
{
public class StartupManagerTests : IFakeStartupCallback
{
private readonly IList<object> _configurationMethodCalledList = new List<object>();
@ -20,16 +19,16 @@ namespace Microsoft.AspNet.Hosting.Tests
[Fact]
public void StartupClassMayHaveHostingServicesInjected()
{
var serviceCollection = new ServiceCollection().AddHosting();
var serviceCollection = new ServiceCollection();
serviceCollection.AddInstance<IFakeStartupCallback>(this);
var services = serviceCollection.BuildServiceProvider();
var loader = services.GetRequiredService<IStartupLoader>();
var diagnosticMessages = new List<string>();
var startup = loader.LoadStartup("Microsoft.AspNet.Hosting.Tests", "WithServices", diagnosticMessages);
var startup = ApplicationStartup.LoadStartupMethods(services, "Microsoft.AspNet.Hosting.Tests", "WithServices", diagnosticMessages);
startup.Invoke(new ApplicationBuilder(services));
var app = new ApplicationBuilder(services);
app.ApplicationServices = startup.ConfigureServicesDelegate(serviceCollection);
startup.ConfigureDelegate(app);
Assert.Equal(2, _configurationMethodCalledList.Count);
}
@ -45,15 +44,14 @@ namespace Microsoft.AspNet.Hosting.Tests
[InlineData("BaseClass")]
public void StartupClassAddsConfigureServicesToApplicationServices(string environment)
{
var services = HostingServices.Create().BuildServiceProvider();
var loader = services.GetRequiredService<IStartupLoader>();
var services = new ServiceCollection().BuildServiceProvider();
var diagnosticMesssages = new List<string>();
var startup = loader.LoadStartup("Microsoft.AspNet.Hosting.Tests", environment ?? "", diagnosticMesssages);
var startup = ApplicationStartup.LoadStartupMethods(services, "Microsoft.AspNet.Hosting.Tests", environment ?? "", diagnosticMesssages);
var app = new ApplicationBuilder(services);
startup.Invoke(app);
app.ApplicationServices = startup.ConfigureServicesDelegate(new ServiceCollection());
startup.ConfigureDelegate(app);
var options = app.ApplicationServices.GetRequiredService<IOptions<FakeOptions>>().Options;
Assert.NotNull(options);
@ -61,92 +59,46 @@ namespace Microsoft.AspNet.Hosting.Tests
Assert.Equal(environment, options.Environment);
}
[Theory]
[InlineData("Null")]
[InlineData("FallbackProvider")]
public void StartupClassConfigureServicesThatFallsbackToApplicationServices(string env)
{
var services = HostingServices.Create().BuildServiceProvider();
var loader = services.GetRequiredService<IStartupLoader>();
var diagnosticMessages = new List<string>();
var startup = loader.LoadStartup("Microsoft.AspNet.Hosting.Tests", env, diagnosticMessages);
var app = new ApplicationBuilder(services);
startup.Invoke(app);
Assert.Equal(services, app.ApplicationServices);
}
// REVIEW: With the manifest change, Since the ConfigureServices are not imported, UseServices will mask what's in ConfigureServices
// This will throw since ConfigureServices consumes manifest and then UseServices will blow up
[Fact(Skip = "Review Failure")]
public void StartupClassWithConfigureServicesAndUseServicesHidesConfigureServices()
{
var services = HostingServices.Create().BuildServiceProvider();
var loader = services.GetRequiredService<IStartupLoader>();
var diagnosticMessages = new List<string>();
var startup = loader.LoadStartup("Microsoft.AspNet.Hosting.Tests", "UseServices", diagnosticMessages);
var app = new ApplicationBuilder(services);
startup.Invoke(app);
Assert.NotNull(app.ApplicationServices.GetRequiredService<FakeService>());
Assert.Null(app.ApplicationServices.GetService<IFakeService>());
var options = app.ApplicationServices.GetRequiredService<IOptions<FakeOptions>>().Options;
Assert.NotNull(options);
Assert.Equal("Configured", options.Message);
Assert.False(options.Configured); // Options never resolved from inner containers
}
[Fact]
public void StartupWithNoConfigureThrows()
{
var serviceCollection = HostingServices.Create();
var serviceCollection = new ServiceCollection();
serviceCollection.AddInstance<IFakeStartupCallback>(this);
var services = serviceCollection.BuildServiceProvider();
var loader = services.GetRequiredService<IStartupLoader>();
var diagnosticMessages = new List<string>();
var ex = Assert.Throws<Exception>(() => loader.LoadStartup("Microsoft.AspNet.Hosting.Tests", "Boom", diagnosticMessages));
var ex = Assert.Throws<InvalidOperationException>(() => ApplicationStartup.LoadStartupMethods(services, "Microsoft.AspNet.Hosting.Tests", "Boom", diagnosticMessages));
Assert.Equal("A method named 'ConfigureBoom' or 'Configure' in the type 'Microsoft.AspNet.Hosting.Fakes.StartupBoom' could not be found.", ex.Message);
}
[Fact]
public void StartupWithConfigureServicesNotResolvedThrows()
public void StartupClassCanHandleConfigureServicesThatReturnsNull()
{
var serviceCollection = HostingServices.Create();
var serviceCollection = new ServiceCollection();
var services = serviceCollection.BuildServiceProvider();
var loader = services.GetRequiredService<IStartupLoader>();
var diagnosticMessages = new List<string>();
var startup = loader.LoadStartup("Microsoft.AspNet.Hosting.Tests", "WithConfigureServicesNotResolved", diagnosticMessages);
var startup = ApplicationStartup.LoadStartupMethods(services, "Microsoft.AspNet.Hosting.Tests", "WithNullConfigureServices", diagnosticMessages);
var app = new ApplicationBuilder(services);
var ex = Assert.Throws<Exception>(() => startup.Invoke(app));
Assert.Equal("Could not resolve a service of type 'System.Int32' for the parameter 'notAService' of method 'Configure' on type 'Microsoft.AspNet.Hosting.Fakes.StartupWithConfigureServicesNotResolved'.", ex.Message);
app.ApplicationServices = startup.ConfigureServicesDelegate(new ServiceCollection());
Assert.NotNull(app.ApplicationServices);
startup.ConfigureDelegate(app);
Assert.NotNull(app.ApplicationServices);
}
[Fact]
public void StartupClassWithConfigureServicesShouldMakeServiceAvailableInConfigure()
{
var serviceCollection = HostingServices.Create();
var serviceCollection = new ServiceCollection();
var services = serviceCollection.BuildServiceProvider();
var loader = services.GetRequiredService<IStartupLoader>();
var app = new ApplicationBuilder(services);
var diagnosticMessages = new List<string>();
var startup = loader.LoadStartup("Microsoft.AspNet.Hosting.Tests", "WithConfigureServices", diagnosticMessages);
var startup = ApplicationStartup.LoadStartupMethods(services, "Microsoft.AspNet.Hosting.Tests", "WithConfigureServices", diagnosticMessages);
startup.Invoke(app);
var app = new ApplicationBuilder(services);
app.ApplicationServices = startup.ConfigureServicesDelegate(serviceCollection);
startup.ConfigureDelegate(app);
var foo = app.ApplicationServices.GetRequiredService<StartupWithConfigureServices.IFoo>();
Assert.True(foo.Invoked);

View File

@ -1,98 +0,0 @@
// 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.Builder;
using Microsoft.AspNet.Http.Core;
using Microsoft.AspNet.RequestContainer;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Logging;
using Xunit;
namespace Microsoft.AspNet.Hosting.Tests
{
public class RequestServicesContainerFacts
{
[Fact]
public void RequestServicesAvailableOnlyAfterRequestServices()
{
var baseServiceProvider = HostingServices.Create().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);
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public void EnsureRequestServicesSetsRequestServices(bool initializeApplicationServices)
{
var baseServiceProvider = HostingServices.Create().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, baseServiceProvider))
{
await next.Invoke(c);
}
});
bool foundRequestServicesAfter = false;
builder.Use(next => async c =>
{
foundRequestServicesAfter = c.RequestServices != null;
await next.Invoke(c);
});
var context = new DefaultHttpContext();
if (initializeApplicationServices)
{
context.ApplicationServices = baseServiceProvider;
}
builder.Build().Invoke(context);
Assert.False(foundRequestServicesBefore);
Assert.True(foundRequestServicesAfter);
}
[Theory]
[InlineData(typeof(IHostingEnvironment))]
[InlineData(typeof(ILoggerFactory))]
[InlineData(typeof(IHttpContextAccessor))]
[InlineData(typeof(IApplicationLifetime))]
public void UseRequestServicesHostingImportedServicesAreDefined(Type service)
{
var baseServiceProvider = HostingServices.Create().BuildServiceProvider();
var builder = new ApplicationBuilder(baseServiceProvider);
builder.UseRequestServices();
var fromAppServices = builder.ApplicationServices.GetRequiredService(service);
Assert.NotNull(fromAppServices);
Assert.Equal(baseServiceProvider.GetRequiredService(service), fromAppServices);
}
}
}

View File

@ -2,7 +2,7 @@
"dependencies": {
"Microsoft.AspNet.Hosting": "1.0.0-*",
"Microsoft.AspNet.Owin": "1.0.0-*",
"Microsoft.AspNet.RequestContainer": "1.0.0-*",
"Microsoft.Framework.OptionsModel": "1.0.0-*",
"xunit.runner.aspnet": "2.0.0-aspnet-*"
},
"frameworks": {

View File

@ -10,7 +10,6 @@ using System.Threading.Tasks;
using Microsoft.AspNet.FeatureModel;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Core;
using Microsoft.AspNet.Http;
using Xunit;
namespace Microsoft.AspNet.TestHost

View File

@ -1,37 +0,0 @@
// 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 System.Runtime.Versioning;
using Microsoft.Framework.Runtime;
namespace Microsoft.AspNet.TestHost
{
public class TestApplicationEnvironment : IApplicationEnvironment
{
public string ApplicationName
{
get { return "Test App environment"; }
}
public string Version
{
get { return "1.0.0"; }
}
public string ApplicationBasePath
{
get { return Environment.CurrentDirectory; }
}
public string Configuration
{
get { return "Test"; }
}
public FrameworkName RuntimeFramework
{
get { return new FrameworkName(".NETFramework", new Version(4, 5)); }
}
}
}

View File

@ -20,9 +20,7 @@ namespace Microsoft.AspNet.TestHost
public TestClientTests()
{
_services = HostingServices.Create().BuildServiceProvider();
_server = TestServer.Create(_services, app => app.Run(ctx => Task.FromResult(0)));
_server = TestServer.Create(app => app.Run(ctx => Task.FromResult(0)));
}
[Fact]
@ -32,7 +30,7 @@ namespace Microsoft.AspNet.TestHost
var expected = "GET Response";
RequestDelegate appDelegate = ctx =>
ctx.Response.WriteAsync(expected);
var server = TestServer.Create(_services, app => app.Run(appDelegate));
var server = TestServer.Create(app => app.Run(appDelegate));
var client = server.CreateClient();
// Act
@ -53,7 +51,7 @@ namespace Microsoft.AspNet.TestHost
Assert.Equal("/", ctx.Request.Path.Value);
return ctx.Response.WriteAsync(expected);
};
var server = TestServer.Create(_services, app => app.Run(appDelegate));
var server = TestServer.Create(app => app.Run(appDelegate));
var client = server.CreateClient();
// Act
@ -74,7 +72,7 @@ namespace Microsoft.AspNet.TestHost
Assert.Equal("/", ctx.Request.Path.Value);
return ctx.Response.WriteAsync(expected);
};
var server = TestServer.Create(_services, app => app.Run(appDelegate));
var server = TestServer.Create(app => app.Run(appDelegate));
var client = server.CreateClient();
// Act
@ -90,7 +88,7 @@ namespace Microsoft.AspNet.TestHost
// Arrange
RequestDelegate appDelegate = ctx =>
ctx.Response.WriteAsync(new StreamReader(ctx.Request.Body).ReadToEnd() + " PUT Response");
var server = TestServer.Create(_services, app => app.Run(appDelegate));
var server = TestServer.Create(app => app.Run(appDelegate));
var client = server.CreateClient();
// Act
@ -107,7 +105,7 @@ namespace Microsoft.AspNet.TestHost
// Arrange
RequestDelegate appDelegate = async ctx =>
await ctx.Response.WriteAsync(new StreamReader(ctx.Request.Body).ReadToEnd() + " POST Response");
var server = TestServer.Create(_services, app => app.Run(appDelegate));
var server = TestServer.Create(app => app.Run(appDelegate));
var client = server.CreateClient();
// Act

View File

@ -21,10 +21,8 @@ namespace Microsoft.AspNet.TestHost
public void CreateWithDelegate()
{
// Arrange
var services = HostingServices.Create().BuildServiceProvider();
// Act & Assert (Does not throw)
TestServer.Create(services, app => { });
TestServer.Create(app => { });
}
[Fact]
@ -37,6 +35,21 @@ namespace Microsoft.AspNet.TestHost
Assert.Throws<InvalidOperationException>(() => TestServer.Create(services, new Startup().Configuration));
}
[Fact]
public async Task RequestServicesAutoCreated()
{
TestServer server = TestServer.Create(app =>
{
app.Run(context =>
{
return context.Response.WriteAsync("RequestServices:" + (context.RequestServices != null));
});
});
string result = await server.CreateClient().GetStringAsync("/path");
Assert.Equal("RequestServices:True", result);
}
[Fact]
public async Task CanAccessLogger()
{
@ -92,7 +105,8 @@ namespace Microsoft.AspNet.TestHost
var accessor = app.ApplicationServices.GetRequiredService<ContextHolder>();
return context.Response.WriteAsync("HasContext:" + (accessor.Accessor.HttpContext != null));
});
}, newHostServices => newHostServices.AddSingleton<ContextHolder>());
},
services => services.AddSingleton<ContextHolder>().BuildServiceProvider());
string result = await server.CreateClient().GetStringAsync("/path");
Assert.Equal("HasContext:True", result);