diff --git a/MetaPackages.sln b/MetaPackages.sln
index 94b2aad881..5fbde25dd9 100644
--- a/MetaPackages.sln
+++ b/MetaPackages.sln
@@ -24,6 +24,20 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{192F
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleApp", "samples\SampleApp\SampleApp.csproj", "{AF5BB04E-92F7-4737-8B98-F86F6244FAB2}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{9E49B5B9-9E72-42FB-B684-90CA1B1BCF9C}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.FunctionalTests", "test\Microsoft.AspNetCore.Tests\Microsoft.AspNetCore.FunctionalTests.csproj", "{C72A756A-D29D-44C7-83D4-821DBE82DBCA}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestSites", "TestSites", "{EC22261D-0DE1-47DE-8F7C-072675D6F5B4}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StartRouteBuilderUrlApp", "test\TestSites\StartRouteBuilderUrlApp\StartRouteBuilderUrlApp.csproj", "{AB42054B-1801-4FEE-B5C3-8529C6D7BFDA}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StartWithIApplicationBuilderUrlApp", "test\TestSites\StartWithIApplicationBuilderUrlApp\StartWithIApplicationBuilderUrlApp.csproj", "{3A85FA52-F601-422E-A42E-9F187DB28492}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StartRequestDelegateUrlApp", "test\TestSites\StartRequestDelegateUrlApp\StartRequestDelegateUrlApp.csproj", "{401C741B-6C7C-4E08-9F09-C3D43D22C0DE}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CreateDefaultBuilderApp", "test\TestSites\CreateDefaultBuilderApp\CreateDefaultBuilderApp.csproj", "{79CF58CE-B020-45D8-BDB5-2D8036BEAD14}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -42,6 +56,26 @@ Global
{AF5BB04E-92F7-4737-8B98-F86F6244FAB2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AF5BB04E-92F7-4737-8B98-F86F6244FAB2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AF5BB04E-92F7-4737-8B98-F86F6244FAB2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C72A756A-D29D-44C7-83D4-821DBE82DBCA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C72A756A-D29D-44C7-83D4-821DBE82DBCA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C72A756A-D29D-44C7-83D4-821DBE82DBCA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C72A756A-D29D-44C7-83D4-821DBE82DBCA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AB42054B-1801-4FEE-B5C3-8529C6D7BFDA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AB42054B-1801-4FEE-B5C3-8529C6D7BFDA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AB42054B-1801-4FEE-B5C3-8529C6D7BFDA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AB42054B-1801-4FEE-B5C3-8529C6D7BFDA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3A85FA52-F601-422E-A42E-9F187DB28492}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3A85FA52-F601-422E-A42E-9F187DB28492}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3A85FA52-F601-422E-A42E-9F187DB28492}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3A85FA52-F601-422E-A42E-9F187DB28492}.Release|Any CPU.Build.0 = Release|Any CPU
+ {401C741B-6C7C-4E08-9F09-C3D43D22C0DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {401C741B-6C7C-4E08-9F09-C3D43D22C0DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {401C741B-6C7C-4E08-9F09-C3D43D22C0DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {401C741B-6C7C-4E08-9F09-C3D43D22C0DE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {79CF58CE-B020-45D8-BDB5-2D8036BEAD14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {79CF58CE-B020-45D8-BDB5-2D8036BEAD14}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {79CF58CE-B020-45D8-BDB5-2D8036BEAD14}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {79CF58CE-B020-45D8-BDB5-2D8036BEAD14}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -51,5 +85,11 @@ Global
{CC8F551E-213A-45E8-AECA-507C4DB4F164} = {ED834E68-51C3-4ADE-ACC8-6BA6D4207C09}
{F92CB7A1-C38E-408C-A7EC-A5C040D041E1} = {97D53BEB-A511-4FBE-B784-AB407D9A219F}
{AF5BB04E-92F7-4737-8B98-F86F6244FAB2} = {192F583C-C4CA-43E5-B31C-D21B7806E274}
+ {C72A756A-D29D-44C7-83D4-821DBE82DBCA} = {9E49B5B9-9E72-42FB-B684-90CA1B1BCF9C}
+ {EC22261D-0DE1-47DE-8F7C-072675D6F5B4} = {9E49B5B9-9E72-42FB-B684-90CA1B1BCF9C}
+ {AB42054B-1801-4FEE-B5C3-8529C6D7BFDA} = {EC22261D-0DE1-47DE-8F7C-072675D6F5B4}
+ {3A85FA52-F601-422E-A42E-9F187DB28492} = {EC22261D-0DE1-47DE-8F7C-072675D6F5B4}
+ {401C741B-6C7C-4E08-9F09-C3D43D22C0DE} = {EC22261D-0DE1-47DE-8F7C-072675D6F5B4}
+ {79CF58CE-B020-45D8-BDB5-2D8036BEAD14} = {EC22261D-0DE1-47DE-8F7C-072675D6F5B4}
EndGlobalSection
EndGlobal
diff --git a/build/dependencies.props b/build/dependencies.props
index dc11d345dd..c2c1448f9a 100644
--- a/build/dependencies.props
+++ b/build/dependencies.props
@@ -1,8 +1,11 @@
+ 0.4.0-*
2.0.0-*
1.0.0-*
4.3.0
2.0.0-*
+ 15.0.0
+ 2.2.0
diff --git a/test/Microsoft.AspNetCore.Tests/Microsoft.AspNetCore.FunctionalTests.csproj b/test/Microsoft.AspNetCore.Tests/Microsoft.AspNetCore.FunctionalTests.csproj
new file mode 100644
index 0000000000..d29ae617ca
--- /dev/null
+++ b/test/Microsoft.AspNetCore.Tests/Microsoft.AspNetCore.FunctionalTests.csproj
@@ -0,0 +1,20 @@
+
+
+
+
+
+ netcoreapp2.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/Microsoft.AspNetCore.Tests/WebHostFunctionalTests.cs b/test/Microsoft.AspNetCore.Tests/WebHostFunctionalTests.cs
new file mode 100644
index 0000000000..f925eb91f4
--- /dev/null
+++ b/test/Microsoft.AspNetCore.Tests/WebHostFunctionalTests.cs
@@ -0,0 +1,139 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Server.IntegrationTesting;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Testing;
+using Xunit;
+using Xunit.Abstractions;
+using Xunit.Sdk;
+
+namespace Microsoft.AspNetCore.Tests
+{
+ public class WebHostFunctionalTests : LoggedTest
+ {
+ private readonly string _testSitesPath;
+
+ public WebHostFunctionalTests(ITestOutputHelper output) : base(output)
+ {
+ _testSitesPath = GetTestSitesPath();
+ }
+
+ [Fact]
+ public async Task Start_RequestDelegate_Url()
+ {
+ await ExecuteStartOrStartWithTest(deploymentResult => deploymentResult.HttpClient.GetAsync(string.Empty), "StartRequestDelegateUrlApp");
+ }
+
+ [Fact]
+ public async Task Start_RouteBuilder_Url()
+ {
+ await ExecuteStartOrStartWithTest(deploymentResult => deploymentResult.HttpClient.GetAsync("/route"), "StartRouteBuilderUrlApp");
+ }
+
+ [Fact]
+ public async Task StartWith_IApplicationBuilder_Url()
+ {
+ await ExecuteStartOrStartWithTest(deploymentResult => deploymentResult.HttpClient.GetAsync(string.Empty), "StartWithIApplicationBuilderUrlApp");
+ }
+
+ [Fact]
+ public async Task CreateDefaultBuilder_InitializeWithDefaults()
+ {
+ var applicationName = "CreateDefaultBuilderApp";
+ await ExecuteTestApp(applicationName, async (deploymentResult, logger) =>
+ {
+ var response = await RetryHelper.RetryRequest(() => deploymentResult.HttpClient.GetAsync(string.Empty), logger, deploymentResult.HostShutdownToken);
+ var errorResponse = await RetryHelper.RetryRequest(() => deploymentResult.HttpClient.GetAsync("/error"), logger, deploymentResult.HostShutdownToken);
+
+ var responseText = await response.Content.ReadAsStringAsync();
+ var errorResponseText = await errorResponse.Content.ReadAsStringAsync();
+ try
+ {
+ // Assert server is Kestrel
+ Assert.Equal("Kestrel", response.Headers.Server.ToString());
+
+ // The application name will be sent in response when all asserts succeed in the test app.
+ Assert.Equal(applicationName, responseText);
+
+ // Assert UseDeveloperExceptionPage is called in WebHostStartupFilter.
+ Assert.Contains("An unhandled exception occurred while processing the request.", errorResponseText);
+ }
+ catch (XunitException)
+ {
+ logger.LogWarning(response.ToString());
+ logger.LogWarning(responseText);
+ throw;
+ }
+ }, setTestEnvVars: true);
+ }
+
+ private async Task ExecuteStartOrStartWithTest(Func> getResponse, string applicationName)
+ {
+ await ExecuteTestApp(applicationName, async (deploymentResult, logger) =>
+ {
+ var response = await RetryHelper.RetryRequest(() => getResponse(deploymentResult), logger, deploymentResult.HostShutdownToken);
+
+ var responseText = await response.Content.ReadAsStringAsync();
+ try
+ {
+ Assert.Equal(applicationName, responseText);
+ }
+ catch (XunitException)
+ {
+ logger.LogWarning(response.ToString());
+ logger.LogWarning(responseText);
+ throw;
+ }
+ });
+ }
+
+ private async Task ExecuteTestApp(string applicationName, Func assertAction, bool setTestEnvVars = false)
+ {
+ using (StartLog(out var loggerFactory, applicationName))
+ {
+ var logger = loggerFactory.CreateLogger(nameof(WebHost.Start));
+ var deploymentParameters = new DeploymentParameters(Path.Combine(_testSitesPath, applicationName), ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64);
+
+ if (setTestEnvVars)
+ {
+ deploymentParameters.EnvironmentVariables.Add(new KeyValuePair("aspnetcore_environment", "Development"));
+ deploymentParameters.EnvironmentVariables.Add(new KeyValuePair("envKey", "envValue"));
+ }
+
+ using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, loggerFactory))
+ {
+ var deploymentResult = await deployer.DeployAsync();
+
+ await assertAction(deploymentResult, logger);
+ }
+ }
+ }
+
+ private static string GetTestSitesPath()
+ {
+ var applicationBasePath = AppContext.BaseDirectory;
+
+ var directoryInfo = new DirectoryInfo(applicationBasePath);
+ do
+ {
+ var solutionFileInfo = new FileInfo(Path.Combine(directoryInfo.FullName, "MetaPackages.sln"));
+ if (solutionFileInfo.Exists)
+ {
+ return Path.GetFullPath(Path.Combine(directoryInfo.FullName, "test", "TestSites"));
+ }
+
+ directoryInfo = directoryInfo.Parent;
+ }
+ while (directoryInfo.Parent != null);
+
+ throw new Exception($"Solution root could not be found using {applicationBasePath}");
+ }
+ }
+}
diff --git a/test/TestSites/CreateDefaultBuilderApp/CreateDefaultBuilderApp.csproj b/test/TestSites/CreateDefaultBuilderApp/CreateDefaultBuilderApp.csproj
new file mode 100644
index 0000000000..0956c47f07
--- /dev/null
+++ b/test/TestSites/CreateDefaultBuilderApp/CreateDefaultBuilderApp.csproj
@@ -0,0 +1,13 @@
+
+
+
+ Exe
+ netcoreapp2.0
+ aspnetcore-CreateDefaultBuilder-20170424224131
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/TestSites/CreateDefaultBuilderApp/Program.cs b/test/TestSites/CreateDefaultBuilderApp/Program.cs
new file mode 100644
index 0000000000..f14aec8f93
--- /dev/null
+++ b/test/TestSites/CreateDefaultBuilderApp/Program.cs
@@ -0,0 +1,110 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using Microsoft.Extensions.Logging.Console;
+using Microsoft.Extensions.Logging.Debug;
+
+namespace CreateDefaultBuilderApp
+{
+ public class Program
+ {
+ static void Main(string[] args)
+ {
+ string responseMessage = string.Empty;
+
+ WebHost.CreateDefaultBuilder(new[] { "--cliKey", "cliValue" })
+ .UseLoggerFactory(new TestLoggerFactory())
+ .ConfigureServices((context, services) =>
+ {
+ responseMessage = GetResponseMessage(context, services);
+ })
+ .Configure(app =>
+ {
+ app.Map("/error", subApp =>
+ {
+ subApp.Run(context => throw new Exception());
+ });
+ app.Run(context =>
+ {
+ return context.Response.WriteAsync(responseMessage);
+ });
+ })
+ .Build().Run();
+ }
+
+ private static string GetResponseMessage(WebHostBuilderContext context, IServiceCollection services)
+ {
+ // Verify ContentRootPath set
+ if (!string.Equals(Directory.GetCurrentDirectory(), context.HostingEnvironment.ContentRootPath, StringComparison.Ordinal))
+ {
+ return $"Current directory incorrect. Expected: {Directory.GetCurrentDirectory()} Actual: {context.HostingEnvironment.ContentRootPath}";
+ }
+
+ // Verify appsettings.json loaded
+ if (!string.Equals("settingsValue", context.Configuration["settingsKey"], StringComparison.Ordinal))
+ {
+ return $"appsettings.json not loaded into Configuration.";
+ }
+
+ // Verify appsettings.environment.json loaded
+ if (!string.Equals("devSettingsValue", context.Configuration["devSettingsKey"], StringComparison.Ordinal))
+ {
+ return $"appsettings.{context.HostingEnvironment.EnvironmentName}.json not loaded into Configuration.";
+ }
+
+ // TODO: Verify UserSecrets loaded
+
+ // Verify environment variables loaded
+ if (!string.Equals("envValue", context.Configuration["envKey"], StringComparison.Ordinal))
+ {
+ return $"Environment variables not loaded into Configuration.";
+ }
+
+ // Verify command line arguments loaded
+ if (!string.Equals("cliValue", context.Configuration["cliKey"], StringComparison.Ordinal))
+ {
+ return $"Command line arguments not loaded into Configuration.";
+ }
+
+ var testLoggerFactory = (TestLoggerFactory)context.LoggerFactory;
+
+ // Verify AddConsole called
+ if (!testLoggerFactory.Providers.Any(provider => provider is ConsoleLoggerProvider))
+ {
+ return $"Console logger not added to ILoggerFactory.";
+ }
+
+ // Verify AddDebug called
+ if (!testLoggerFactory.Providers.Any(provider => provider is DebugLoggerProvider))
+ {
+ return $"Debug logger not added to ILoggerFactory.";
+ }
+
+ // TODO: Verify UseIISIntegration called
+
+ return context.HostingEnvironment.ApplicationName;
+ }
+
+ private class TestLoggerFactory : ILoggerFactory
+ {
+ public IList Providers { get; } = new List();
+
+ public void AddProvider(ILoggerProvider provider) => Providers.Add(provider);
+
+ public ILogger CreateLogger(string categoryName) => NullLogger.Instance;
+
+ public void Dispose() { }
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/TestSites/CreateDefaultBuilderApp/appsettings.Development.json b/test/TestSites/CreateDefaultBuilderApp/appsettings.Development.json
new file mode 100644
index 0000000000..d2ccc50d64
--- /dev/null
+++ b/test/TestSites/CreateDefaultBuilderApp/appsettings.Development.json
@@ -0,0 +1,3 @@
+{
+ "devSettingsKey": "devSettingsValue"
+}
diff --git a/test/TestSites/CreateDefaultBuilderApp/appsettings.json b/test/TestSites/CreateDefaultBuilderApp/appsettings.json
new file mode 100644
index 0000000000..bc5ff92c67
--- /dev/null
+++ b/test/TestSites/CreateDefaultBuilderApp/appsettings.json
@@ -0,0 +1,3 @@
+{
+ "settingsKey": "settingsValue"
+}
diff --git a/test/TestSites/StartRequestDelegateUrlApp/Program.cs b/test/TestSites/StartRequestDelegateUrlApp/Program.cs
new file mode 100644
index 0000000000..351f870b56
--- /dev/null
+++ b/test/TestSites/StartRequestDelegateUrlApp/Program.cs
@@ -0,0 +1,43 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Threading;
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Hosting.Server.Features;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace StartRequestDelegateUrlApp
+{
+ public class Program
+ {
+ static void Main(string[] args)
+ {
+ var messageSent = new ManualResetEventSlim(false);
+
+ using (var host = WebHost.Start("http://127.0.0.1:0", async context =>
+ {
+ // Respond with the ApplicationName.
+ var env = context.RequestServices.GetRequiredService();
+ await context.Response.WriteAsync(env.ApplicationName);
+ messageSent.Set();
+ }))
+ {
+ // Need these for test deployer to consider host deployment successful
+ // The address written here is used by the client to send requests
+ var addresses = host.ServerFeatures.Get().Addresses;
+ foreach (var address in addresses)
+ {
+ Console.WriteLine($"Now listening on: {address}");
+ }
+ Console.WriteLine("Application started. Press Ctrl+C to shut down.");
+
+ // Shut down after message sent or timeout
+ messageSent.Wait(TimeSpan.FromSeconds(30));
+
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/TestSites/StartRequestDelegateUrlApp/StartRequestDelegateUrlApp.csproj b/test/TestSites/StartRequestDelegateUrlApp/StartRequestDelegateUrlApp.csproj
new file mode 100644
index 0000000000..0c089dbc33
--- /dev/null
+++ b/test/TestSites/StartRequestDelegateUrlApp/StartRequestDelegateUrlApp.csproj
@@ -0,0 +1,12 @@
+
+
+
+ Exe
+ netcoreapp2.0
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/TestSites/StartRouteBuilderUrlApp/Program.cs b/test/TestSites/StartRouteBuilderUrlApp/Program.cs
new file mode 100644
index 0000000000..5aa13ea396
--- /dev/null
+++ b/test/TestSites/StartRouteBuilderUrlApp/Program.cs
@@ -0,0 +1,43 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Threading;
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Hosting.Server.Features;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Routing;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace StartRequestDelegateUrlApp
+{
+ public class Program
+ {
+ static void Main(string[] args)
+ {
+ var messageSent = new ManualResetEventSlim(false);
+
+ using (var host = WebHost.Start("http://127.0.0.1:0", router =>
+ router.MapGet("route", async (req, res, data) =>
+ {
+ var env = req.HttpContext.RequestServices.GetRequiredService();
+ await res.WriteAsync(env.ApplicationName);
+ messageSent.Set();
+ })))
+ {
+ // Need these for test deployer to consider host deployment successful
+ // The address written here is used by the client to send requests
+ var addresses = host.ServerFeatures.Get().Addresses;
+ foreach (var address in addresses)
+ {
+ Console.WriteLine($"Now listening on: {address}");
+ }
+ Console.WriteLine("Application started. Press Ctrl+C to shut down.");
+
+ // Shut down after message sent or timeout
+ messageSent.Wait(TimeSpan.FromSeconds(30));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/TestSites/StartRouteBuilderUrlApp/StartRouteBuilderUrlApp.csproj b/test/TestSites/StartRouteBuilderUrlApp/StartRouteBuilderUrlApp.csproj
new file mode 100644
index 0000000000..0c089dbc33
--- /dev/null
+++ b/test/TestSites/StartRouteBuilderUrlApp/StartRouteBuilderUrlApp.csproj
@@ -0,0 +1,12 @@
+
+
+
+ Exe
+ netcoreapp2.0
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/TestSites/StartWithIApplicationBuilderUrlApp/Program.cs b/test/TestSites/StartWithIApplicationBuilderUrlApp/Program.cs
new file mode 100644
index 0000000000..f904dcff57
--- /dev/null
+++ b/test/TestSites/StartWithIApplicationBuilderUrlApp/Program.cs
@@ -0,0 +1,45 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Threading;
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Hosting.Server.Features;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace StartWithIApplicationBuilderUrlApp
+{
+ public class Program
+ {
+ static void Main(string[] args)
+ {
+ var messageSent = new ManualResetEventSlim(false);
+
+ using (var host = WebHost.StartWith("http://127.0.0.1:0", app =>
+ {
+ app.Run(async context =>
+ {
+ var env = context.RequestServices.GetRequiredService();
+ await context.Response.WriteAsync(env.ApplicationName);
+ messageSent.Set();
+ });
+ }))
+ {
+ // Need these for test deployer to consider host deployment successful
+ // The address written here is used by the client to send requests
+ var addresses = host.ServerFeatures.Get().Addresses;
+ foreach (var address in addresses)
+ {
+ Console.WriteLine($"Now listening on: {address}");
+ }
+ Console.WriteLine("Application started. Press Ctrl+C to shut down.");
+
+ // Shut down after message sent or timeout
+ messageSent.Wait(TimeSpan.FromSeconds(30));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/TestSites/StartWithIApplicationBuilderUrlApp/StartWithIApplicationBuilderUrlApp.csproj b/test/TestSites/StartWithIApplicationBuilderUrlApp/StartWithIApplicationBuilderUrlApp.csproj
new file mode 100644
index 0000000000..0c089dbc33
--- /dev/null
+++ b/test/TestSites/StartWithIApplicationBuilderUrlApp/StartWithIApplicationBuilderUrlApp.csproj
@@ -0,0 +1,12 @@
+
+
+
+ Exe
+ netcoreapp2.0
+
+
+
+
+
+
+
\ No newline at end of file