diff --git a/src/Metapackages/.gitignore b/src/Metapackages/.gitignore
new file mode 100644
index 0000000000..3af0091ea3
--- /dev/null
+++ b/src/Metapackages/.gitignore
@@ -0,0 +1,37 @@
+[Oo]bj/
+[Bb]in/
+TestResults/
+.nuget/
+_ReSharper.*/
+packages/
+artifacts/
+PublishProfiles/
+*.user
+*.suo
+*.cache
+*.docstates
+_ReSharper.*
+nuget.exe
+*net45.csproj
+*net451.csproj
+*k10.csproj
+*.psess
+*.vsp
+*.pidb
+*.userprefs
+*DS_Store
+*.ncrunchsolution
+*.*sdf
+*.ipch
+*.sln.ide
+project.lock.json
+.vs
+.vscode/
+.build/
+.testPublish/
+global.json
+
+# Dependencies from pre-requisite builds
+.deps/
+.rw/
+.ro/
diff --git a/src/Metapackages/Directory.Build.props b/src/Metapackages/Directory.Build.props
new file mode 100644
index 0000000000..9bcc46cef9
--- /dev/null
+++ b/src/Metapackages/Directory.Build.props
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+ Microsoft ASP.NET Core
+ https://github.com/aspnet/MetaPackages
+ git
+ $(MSBuildThisFileDirectory)
+ false
+ $(MSBuildThisFileDirectory)build\Key.snk
+ true
+ true
+ true
+
+
diff --git a/src/Metapackages/Directory.Build.targets b/src/Metapackages/Directory.Build.targets
new file mode 100644
index 0000000000..53b3f6e1da
--- /dev/null
+++ b/src/Metapackages/Directory.Build.targets
@@ -0,0 +1,7 @@
+
+
+ $(MicrosoftNETCoreApp20PackageVersion)
+ $(MicrosoftNETCoreApp21PackageVersion)
+ $(NETStandardLibrary20PackageVersion)
+
+
diff --git a/src/Metapackages/MetaPackages.sln b/src/Metapackages/MetaPackages.sln
new file mode 100644
index 0000000000..659427dfcb
--- /dev/null
+++ b/src/Metapackages/MetaPackages.sln
@@ -0,0 +1,116 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.27005.2
+MinimumVisualStudioVersion = 15.0.26730.03
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{ED834E68-51C3-4ADE-ACC8-6BA6D4207C09}"
+ ProjectSection(SolutionItems) = preProject
+ src\Directory.Build.props = src\Directory.Build.props
+ EndProjectSection
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore", "src\Microsoft.AspNetCore\Microsoft.AspNetCore.csproj", "{6F3D43F7-9546-4B41-AF04-CF4708B62051}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{97D53BEB-A511-4FBE-B784-AB407D9A219F}"
+ ProjectSection(SolutionItems) = preProject
+ Directory.Build.props = Directory.Build.props
+ Directory.Build.targets = Directory.Build.targets
+ NuGet.config = NuGet.config
+ version.xml = version.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{F92CB7A1-C38E-408C-A7EC-A5C040D041E1}"
+ ProjectSection(SolutionItems) = preProject
+ build\dependencies.props = build\dependencies.props
+ build\repo.targets = build\repo.targets
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{192F583C-C4CA-43E5-B31C-D21B7806E274}"
+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.FunctionalTests\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
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DependencyInjectionApp", "test\TestSites\DependencyInjectionApp\DependencyInjectionApp.csproj", "{65FE2E38-4529-4C93-A7B0-CF12DD7A70C3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CreateDefaultBuilderOfTApp", "test\TestSites\CreateDefaultBuilderOfTApp\CreateDefaultBuilderOfTApp.csproj", "{A922B5AC-836B-44F4-83F1-3CB9EB08A3F8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Tests", "test\Microsoft.AspNetCore.Tests\Microsoft.AspNetCore.Tests.csproj", "{BD08F027-3BB9-427B-9367-19534B7376B3}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {6F3D43F7-9546-4B41-AF04-CF4708B62051}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6F3D43F7-9546-4B41-AF04-CF4708B62051}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6F3D43F7-9546-4B41-AF04-CF4708B62051}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6F3D43F7-9546-4B41-AF04-CF4708B62051}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AF5BB04E-92F7-4737-8B98-F86F6244FAB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {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
+ {65FE2E38-4529-4C93-A7B0-CF12DD7A70C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {65FE2E38-4529-4C93-A7B0-CF12DD7A70C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {65FE2E38-4529-4C93-A7B0-CF12DD7A70C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {65FE2E38-4529-4C93-A7B0-CF12DD7A70C3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A922B5AC-836B-44F4-83F1-3CB9EB08A3F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A922B5AC-836B-44F4-83F1-3CB9EB08A3F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A922B5AC-836B-44F4-83F1-3CB9EB08A3F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A922B5AC-836B-44F4-83F1-3CB9EB08A3F8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BD08F027-3BB9-427B-9367-19534B7376B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BD08F027-3BB9-427B-9367-19534B7376B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BD08F027-3BB9-427B-9367-19534B7376B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BD08F027-3BB9-427B-9367-19534B7376B3}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {6F3D43F7-9546-4B41-AF04-CF4708B62051} = {ED834E68-51C3-4ADE-ACC8-6BA6D4207C09}
+ {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}
+ {65FE2E38-4529-4C93-A7B0-CF12DD7A70C3} = {EC22261D-0DE1-47DE-8F7C-072675D6F5B4}
+ {A922B5AC-836B-44F4-83F1-3CB9EB08A3F8} = {EC22261D-0DE1-47DE-8F7C-072675D6F5B4}
+ {BD08F027-3BB9-427B-9367-19534B7376B3} = {9E49B5B9-9E72-42FB-B684-90CA1B1BCF9C}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {A666E9B0-125B-4975-B35B-09A6D68A5047}
+ EndGlobalSection
+EndGlobal
diff --git a/src/Metapackages/NuGetPackageVerifier.json b/src/Metapackages/NuGetPackageVerifier.json
new file mode 100644
index 0000000000..b153ab1515
--- /dev/null
+++ b/src/Metapackages/NuGetPackageVerifier.json
@@ -0,0 +1,7 @@
+{
+ "Default": {
+ "rules": [
+ "DefaultCompositeRule"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/src/Metapackages/README.md b/src/Metapackages/README.md
new file mode 100644
index 0000000000..d35e5f0866
--- /dev/null
+++ b/src/Metapackages/README.md
@@ -0,0 +1,7 @@
+Meta packages
+========
+
+This repo contains NuGet meta packages that help quickly reference sets of common packages.
+
+This project is part of ASP.NET Core. You can find samples, documentation and getting started instructions for ASP.NET Core at the [Home](https://github.com/aspnet/home) repo.
+
diff --git a/src/Metapackages/build/Key.snk b/src/Metapackages/build/Key.snk
new file mode 100644
index 0000000000..e10e4889c1
Binary files /dev/null and b/src/Metapackages/build/Key.snk differ
diff --git a/src/Metapackages/build/dependencies.props b/src/Metapackages/build/dependencies.props
new file mode 100644
index 0000000000..bca0b5e999
--- /dev/null
+++ b/src/Metapackages/build/dependencies.props
@@ -0,0 +1,41 @@
+
+
+ $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
+
+
+
+
+ 2.1.3-rtm-15802
+ 2.1.1
+ 2.1.1
+ 2.1.1
+ 2.1.1
+ 2.1.1
+ 0.5.1
+ 2.1.2
+ 2.1.2
+ 2.1.1
+ 2.1.1
+ 2.1.1
+ 2.1.1
+ 2.1.1
+ 2.1.1
+ 2.1.1
+ 2.1.1
+ 2.1.1
+ 2.1.1
+ 2.0.0
+ 2.1.2
+ 15.6.1
+ 4.7.49
+ 2.0.3
+ 2.3.1
+ 2.4.0-beta.1.build3945
+
+
+
+
+
+
+
+
diff --git a/src/Metapackages/build/repo.props b/src/Metapackages/build/repo.props
new file mode 100644
index 0000000000..dab1601c88
--- /dev/null
+++ b/src/Metapackages/build/repo.props
@@ -0,0 +1,15 @@
+
+
+
+
+
+ Internal.AspNetCore.Universe.Lineup
+ 2.1.0-rc1-*
+ https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json
+
+
+
+
+
+
+
diff --git a/src/Metapackages/build/sources.props b/src/Metapackages/build/sources.props
new file mode 100644
index 0000000000..9215df9751
--- /dev/null
+++ b/src/Metapackages/build/sources.props
@@ -0,0 +1,17 @@
+
+
+
+
+ $(DotNetRestoreSources)
+
+ $(RestoreSources);
+ https://dotnet.myget.org/F/dotnet-core/api/v3/index.json;
+ https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json;
+ https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json;
+
+
+ $(RestoreSources);
+ https://api.nuget.org/v3/index.json;
+
+
+
diff --git a/src/Metapackages/samples/SampleApp/Program.cs b/src/Metapackages/samples/SampleApp/Program.cs
new file mode 100644
index 0000000000..b5eb900273
--- /dev/null
+++ b/src/Metapackages/samples/SampleApp/Program.cs
@@ -0,0 +1,94 @@
+// 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 Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Routing;
+
+namespace SampleApp
+{
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ HelloWorld();
+
+ CustomUrl();
+
+ CustomRouter();
+
+ CustomApplicationBuilder();
+
+ StartupClass(args);
+ }
+
+ private static void HelloWorld()
+ {
+ using (WebHost.Start(context => context.Response.WriteAsync("Hello, World!")))
+ {
+ //host.WaitForShutdown(); // TODO: https://github.com/aspnet/Hosting/issues/1022
+ Console.WriteLine("Running HelloWorld: Press any key to shutdown and start the next sample...");
+ Console.ReadKey();
+ }
+ }
+
+ private static void CustomUrl()
+ {
+ // Changing the listening URL
+ using (WebHost.Start("http://localhost:8080", context => context.Response.WriteAsync("Hello, World!")))
+ {
+ //host.WaitForShutdown(); // TODO: https://github.com/aspnet/Hosting/issues/1022
+ Console.WriteLine("Running CustomUrl: Press any key to shutdown and start the next sample...");
+ Console.ReadKey();
+ }
+ }
+
+ private static void CustomRouter()
+ {
+ // Using a router
+ using (WebHost.Start(router => router
+ .MapGet("hello/{name}", (req, res, data) => res.WriteAsync($"Hello, {data.Values["name"]}"))
+ .MapGet("goodbye/{name}", (req, res, data) => res.WriteAsync($"Goodbye, {data.Values["name"]}"))
+ .MapGet("throw/{message?}", (req, res, data) => throw new Exception((string)data.Values["message"] ?? "Uh oh!"))
+ .MapGet("{greeting}/{name}", (req, res, data) => res.WriteAsync($"{data.Values["greeting"]}, {data.Values["name"]}"))
+ .MapGet("", (req, res, data) => res.WriteAsync($"Hello, World!"))))
+ {
+ //host.WaitForShutdown(); // TODO: https://github.com/aspnet/Hosting/issues/1022
+ Console.WriteLine("Running CustomRouter: Press any key to shutdown and start the next sample...");
+ Console.ReadKey();
+ }
+ }
+
+ private static void CustomApplicationBuilder()
+ {
+ // Using a application builder
+ using (WebHost.StartWith(app =>
+ {
+ app.UseStaticFiles();
+ app.Run(async context =>
+ {
+ await context.Response.WriteAsync("Hello, World!");
+ });
+ }))
+ {
+ //host.WaitForShutdown(); // TODO: https://github.com/aspnet/Hosting/issues/1022
+ Console.WriteLine("Running CustomApplicationBuilder: Press any key to shutdown and start the next sample...");
+ Console.ReadKey();
+ }
+ }
+
+ private static void StartupClass(string[] args)
+ {
+ // Using defaults with a Startup class
+ using (var host = WebHost.CreateDefaultBuilder(args)
+ .UseStartup()
+ .Build())
+ {
+ host.Run();
+ }
+ }
+ }
+}
diff --git a/src/Metapackages/samples/SampleApp/Properties/launchSettings.json b/src/Metapackages/samples/SampleApp/Properties/launchSettings.json
new file mode 100644
index 0000000000..f0370cf22b
--- /dev/null
+++ b/src/Metapackages/samples/SampleApp/Properties/launchSettings.json
@@ -0,0 +1,27 @@
+{
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:53432/",
+ "sslPort": 0
+ }
+ },
+ "profiles": {
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "SampleApp": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "applicationUrl": "http://localhost:53433"
+ }
+ }
+}
diff --git a/src/Metapackages/samples/SampleApp/SampleApp.csproj b/src/Metapackages/samples/SampleApp/SampleApp.csproj
new file mode 100644
index 0000000000..622f64cc4c
--- /dev/null
+++ b/src/Metapackages/samples/SampleApp/SampleApp.csproj
@@ -0,0 +1,16 @@
+
+
+
+ netcoreapp2.1;net461
+ aspnetcore-MetaPackagesSampleApp-20170406180413
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Metapackages/samples/SampleApp/Startup.cs b/src/Metapackages/samples/SampleApp/Startup.cs
new file mode 100644
index 0000000000..287fffd27a
--- /dev/null
+++ b/src/Metapackages/samples/SampleApp/Startup.cs
@@ -0,0 +1,26 @@
+// 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 Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace SampleApp
+{
+ public class Startup
+ {
+ public void ConfigureServices(IServiceCollection services)
+ {
+
+ }
+
+ public void Configure(IApplicationBuilder app, IHostingEnvironment env)
+ {
+ app.Run(async (context) =>
+ {
+ await context.Response.WriteAsync($"Hello from {nameof(Startup)}!");
+ });
+ }
+ }
+}
diff --git a/src/Metapackages/samples/SampleApp/appsettings.json b/src/Metapackages/samples/SampleApp/appsettings.json
new file mode 100644
index 0000000000..6a1c35ebcf
--- /dev/null
+++ b/src/Metapackages/samples/SampleApp/appsettings.json
@@ -0,0 +1,50 @@
+{
+ "AllowedHosts": "example.com;localhost",
+ "Kestrel": {
+ "EndPoints": {
+ "Http": {
+ "Url": "http://localhost:5005"
+ }
+
+ // To enable HTTPS using a certificate file, set the path to a .pfx file in
+ // the "Path" property below and configure the password in user secrets.
+ // The "Password" property should be set in user secrets.
+ //"HttpsInlineCertFile": {
+ // "Url": "http://localhost:5005"
+ // "Certificate": {
+ // "Path": "",
+ // "Password: ""
+ // }
+ //},
+
+ //"HttpsInlineCertStore": {
+ // "Url": "http://localhost:5005"
+ // "Certificate": {
+ // "Subject": "",
+ // "Store": "",
+ // "Location": "",
+ // "AllowInvalid": "" // Set to "true" to allow invalid certificates (e.g. expired)
+ // }
+ //},
+
+ // This uses the cert defined under Certificates/Default or the development cert.
+ //"HttpsDefaultCert": {
+ // "Url": "http://localhost:5005"
+ //}
+ }
+ },
+ "Certificates": {
+ //"Default": {
+ // "Path": "",
+ // "Password": ""
+ //},
+
+ // From cert store:
+ //"Default": {
+ // "Subject": "",
+ // "Store": "",
+ // "Location": "",
+ // "AllowInvalid": "" // Set to "true" to allow invalid certificates (e.g. expired certificates)
+ //}
+ }
+}
diff --git a/src/Metapackages/samples/SampleApp/wwwroot/htmlpage.html b/src/Metapackages/samples/SampleApp/wwwroot/htmlpage.html
new file mode 100644
index 0000000000..ab3af6d3f7
--- /dev/null
+++ b/src/Metapackages/samples/SampleApp/wwwroot/htmlpage.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+ A static HTML file.
+
+
\ No newline at end of file
diff --git a/src/Metapackages/src/Directory.Build.props b/src/Metapackages/src/Directory.Build.props
new file mode 100644
index 0000000000..410f24daa9
--- /dev/null
+++ b/src/Metapackages/src/Directory.Build.props
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/src/Metapackages/src/Microsoft.AspNetCore/HostFilteringStartupFilter.cs b/src/Metapackages/src/Microsoft.AspNetCore/HostFilteringStartupFilter.cs
new file mode 100644
index 0000000000..56c6d9c34f
--- /dev/null
+++ b/src/Metapackages/src/Microsoft.AspNetCore/HostFilteringStartupFilter.cs
@@ -0,0 +1,21 @@
+// 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 Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+
+namespace Microsoft.AspNetCore
+{
+ internal class HostFilteringStartupFilter : IStartupFilter
+ {
+ public Action Configure(Action next)
+ {
+ return app =>
+ {
+ app.UseHostFiltering();
+ next(app);
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Metapackages/src/Microsoft.AspNetCore/Microsoft.AspNetCore.csproj b/src/Metapackages/src/Microsoft.AspNetCore/Microsoft.AspNetCore.csproj
new file mode 100644
index 0000000000..e52a4f74ed
--- /dev/null
+++ b/src/Metapackages/src/Microsoft.AspNetCore/Microsoft.AspNetCore.csproj
@@ -0,0 +1,30 @@
+
+
+
+ netstandard2.0
+ aspnetcore
+ Microsoft.AspNetCore
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Metapackages/src/Microsoft.AspNetCore/WebHost.cs b/src/Metapackages/src/Microsoft.AspNetCore/WebHost.cs
new file mode 100644
index 0000000000..8c49d2eb23
--- /dev/null
+++ b/src/Metapackages/src/Microsoft.AspNetCore/WebHost.cs
@@ -0,0 +1,241 @@
+// 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.IO;
+using System.Reflection;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.HostFiltering;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Routing;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+
+namespace Microsoft.AspNetCore
+{
+ ///
+ /// Provides convenience methods for creating instances of and with pre-configured defaults.
+ ///
+ public static class WebHost
+ {
+ ///
+ /// Initializes and starts a new with pre-configured defaults.
+ /// See for details.
+ ///
+ /// A delegate that handles requests to the application.
+ /// A started that hosts the application.
+ public static IWebHost Start(RequestDelegate app) =>
+ Start(url: null, app: app);
+
+ ///
+ /// Initializes and starts a new with pre-configured defaults.
+ /// See for details.
+ ///
+ /// The URL the hosted application will listen on.
+ /// A delegate that handles requests to the application.
+ /// A started that hosts the application.
+ public static IWebHost Start(string url, RequestDelegate app)
+ {
+ var startupAssemblyName = app.GetMethodInfo().DeclaringType.GetTypeInfo().Assembly.GetName().Name;
+ return StartWith(url: url, configureServices: null, app: appBuilder => appBuilder.Run(app), applicationName: startupAssemblyName);
+ }
+
+ ///
+ /// Initializes and starts a new with pre-configured defaults.
+ /// See for details.
+ ///
+ /// A delegate that configures the router for handling requests to the application.
+ /// A started that hosts the application.
+ public static IWebHost Start(Action routeBuilder) =>
+ Start(url: null, routeBuilder: routeBuilder);
+
+ ///
+ /// Initializes and starts a new with pre-configured defaults.
+ /// See for details.
+ ///
+ /// The URL the hosted application will listen on.
+ /// A delegate that configures the router for handling requests to the application.
+ /// A started that hosts the application.
+ public static IWebHost Start(string url, Action routeBuilder)
+ {
+ var startupAssemblyName = routeBuilder.GetMethodInfo().DeclaringType.GetTypeInfo().Assembly.GetName().Name;
+ return StartWith(url, services => services.AddRouting(), appBuilder => appBuilder.UseRouter(routeBuilder), applicationName: startupAssemblyName);
+ }
+
+ ///
+ /// Initializes and starts a new with pre-configured defaults.
+ /// See for details.
+ ///
+ /// The delegate that configures the .
+ /// A started that hosts the application.
+ public static IWebHost StartWith(Action app) =>
+ StartWith(url: null, app: app);
+
+ ///
+ /// Initializes and starts a new with pre-configured defaults.
+ /// See for details.
+ ///
+ /// The URL the hosted application will listen on.
+ /// The delegate that configures the .
+ /// A started that hosts the application.
+ public static IWebHost StartWith(string url, Action app) =>
+ StartWith(url: url, configureServices: null, app: app, applicationName: null);
+
+ private static IWebHost StartWith(string url, Action configureServices, Action app, string applicationName)
+ {
+ var builder = CreateDefaultBuilder();
+
+ if (!string.IsNullOrEmpty(url))
+ {
+ builder.UseUrls(url);
+ }
+
+ if (configureServices != null)
+ {
+ builder.ConfigureServices(configureServices);
+ }
+
+ builder.Configure(app);
+
+ if (!string.IsNullOrEmpty(applicationName))
+ {
+ builder.UseSetting(WebHostDefaults.ApplicationKey, applicationName);
+ }
+
+ var host = builder.Build();
+
+ host.Start();
+
+ return host;
+ }
+
+ ///
+ /// Initializes a new instance of the class with pre-configured defaults.
+ ///
+ ///
+ /// The following defaults are applied to the returned :
+ /// use Kestrel as the web server and configure it using the application's configuration providers,
+ /// set the to the result of ,
+ /// load from 'appsettings.json' and 'appsettings.[].json',
+ /// load from User Secrets when is 'Development' using the entry assembly,
+ /// load from environment variables,
+ /// configures the to log to the console and debug output,
+ /// enables IIS integration,
+ /// and enables the ability for frameworks to bind their options to their default configuration sections.
+ ///
+ /// The initialized .
+ public static IWebHostBuilder CreateDefaultBuilder() =>
+ CreateDefaultBuilder(args: null);
+
+ ///
+ /// Initializes a new instance of the class with pre-configured defaults.
+ ///
+ ///
+ /// The following defaults are applied to the returned :
+ /// use Kestrel as the web server and configure it using the application's configuration providers,
+ /// set the to the result of ,
+ /// load from 'appsettings.json' and 'appsettings.[].json',
+ /// load from User Secrets when is 'Development' using the entry assembly,
+ /// load from environment variables,
+ /// load from supplied command line args,
+ /// configures the to log to the console and debug output,
+ /// enables IIS integration,
+ /// and enables the ability for frameworks to bind their options to their default configuration sections.
+ ///
+ /// The command line args.
+ /// The initialized .
+ public static IWebHostBuilder CreateDefaultBuilder(string[] args)
+ {
+ var builder = new WebHostBuilder()
+ .UseKestrel((builderContext, options) =>
+ {
+ options.Configure(builderContext.Configuration.GetSection("Kestrel"));
+ })
+ .UseContentRoot(Directory.GetCurrentDirectory())
+ .ConfigureAppConfiguration((hostingContext, config) =>
+ {
+ var env = hostingContext.HostingEnvironment;
+
+ config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
+ .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
+
+ if (env.IsDevelopment())
+ {
+ var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
+ if (appAssembly != null)
+ {
+ config.AddUserSecrets(appAssembly, optional: true);
+ }
+ }
+
+ config.AddEnvironmentVariables();
+
+ if (args != null)
+ {
+ config.AddCommandLine(args);
+ }
+ })
+ .ConfigureLogging((hostingContext, logging) =>
+ {
+ logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
+ logging.AddConsole();
+ logging.AddDebug();
+ })
+ .ConfigureServices((hostingContext, services) =>
+ {
+ // Fallback
+ services.PostConfigure(options =>
+ {
+ if (options.AllowedHosts == null || options.AllowedHosts.Count == 0)
+ {
+ // "AllowedHosts": "localhost;127.0.0.1;[::1]"
+ var hosts = hostingContext.Configuration["AllowedHosts"]?.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
+ // Fall back to "*" to disable.
+ options.AllowedHosts = (hosts?.Length > 0 ? hosts : new[] { "*" });
+ }
+ });
+ // Change notification
+ services.AddSingleton>(
+ new ConfigurationChangeTokenSource(hostingContext.Configuration));
+
+ services.AddTransient();
+ })
+ .UseIISIntegration()
+ .UseDefaultServiceProvider((context, options) =>
+ {
+ options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
+ });
+
+ if (args != null)
+ {
+ builder.UseConfiguration(new ConfigurationBuilder().AddCommandLine(args).Build());
+ }
+
+ return builder;
+ }
+
+ ///
+ /// Initializes a new instance of the class with pre-configured defaults using typed Startup.
+ ///
+ ///
+ /// The following defaults are applied to the returned :
+ /// use Kestrel as the web server and configure it using the application's configuration providers,
+ /// set the to the result of ,
+ /// load from 'appsettings.json' and 'appsettings.[].json',
+ /// load from User Secrets when is 'Development' using the entry assembly,
+ /// load from environment variables,
+ /// load from supplied command line args,
+ /// configures the to log to the console and debug output,
+ /// enables IIS integration,
+ /// enables the ability for frameworks to bind their options to their default configuration sections.
+ ///
+ /// The type containing the startup methods for the application.
+ /// The command line args.
+ /// The initialized .
+ public static IWebHostBuilder CreateDefaultBuilder(string[] args) where TStartup : class =>
+ CreateDefaultBuilder(args).UseStartup();
+ }
+}
diff --git a/src/Metapackages/src/Microsoft.AspNetCore/baseline.netcore.json b/src/Metapackages/src/Microsoft.AspNetCore/baseline.netcore.json
new file mode 100644
index 0000000000..482a58e908
--- /dev/null
+++ b/src/Metapackages/src/Microsoft.AspNetCore/baseline.netcore.json
@@ -0,0 +1,136 @@
+{
+ "AssemblyIdentity": "Microsoft.AspNetCore, Version=2.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60",
+ "Types": [
+ {
+ "Name": "Microsoft.AspNetCore.WebHost",
+ "Visibility": "Public",
+ "Kind": "Class",
+ "Abstract": true,
+ "Static": true,
+ "Sealed": true,
+ "ImplementedInterfaces": [],
+ "Members": [
+ {
+ "Kind": "Method",
+ "Name": "Start",
+ "Parameters": [
+ {
+ "Name": "app",
+ "Type": "Microsoft.AspNetCore.Http.RequestDelegate"
+ }
+ ],
+ "ReturnType": "Microsoft.AspNetCore.Hosting.IWebHost",
+ "Static": true,
+ "Visibility": "Public",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Method",
+ "Name": "Start",
+ "Parameters": [
+ {
+ "Name": "url",
+ "Type": "System.String"
+ },
+ {
+ "Name": "app",
+ "Type": "Microsoft.AspNetCore.Http.RequestDelegate"
+ }
+ ],
+ "ReturnType": "Microsoft.AspNetCore.Hosting.IWebHost",
+ "Static": true,
+ "Visibility": "Public",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Method",
+ "Name": "Start",
+ "Parameters": [
+ {
+ "Name": "routeBuilder",
+ "Type": "System.Action"
+ }
+ ],
+ "ReturnType": "Microsoft.AspNetCore.Hosting.IWebHost",
+ "Static": true,
+ "Visibility": "Public",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Method",
+ "Name": "Start",
+ "Parameters": [
+ {
+ "Name": "url",
+ "Type": "System.String"
+ },
+ {
+ "Name": "routeBuilder",
+ "Type": "System.Action"
+ }
+ ],
+ "ReturnType": "Microsoft.AspNetCore.Hosting.IWebHost",
+ "Static": true,
+ "Visibility": "Public",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Method",
+ "Name": "StartWith",
+ "Parameters": [
+ {
+ "Name": "app",
+ "Type": "System.Action"
+ }
+ ],
+ "ReturnType": "Microsoft.AspNetCore.Hosting.IWebHost",
+ "Static": true,
+ "Visibility": "Public",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Method",
+ "Name": "StartWith",
+ "Parameters": [
+ {
+ "Name": "url",
+ "Type": "System.String"
+ },
+ {
+ "Name": "app",
+ "Type": "System.Action"
+ }
+ ],
+ "ReturnType": "Microsoft.AspNetCore.Hosting.IWebHost",
+ "Static": true,
+ "Visibility": "Public",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Method",
+ "Name": "CreateDefaultBuilder",
+ "Parameters": [],
+ "ReturnType": "Microsoft.AspNetCore.Hosting.IWebHostBuilder",
+ "Static": true,
+ "Visibility": "Public",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Method",
+ "Name": "CreateDefaultBuilder",
+ "Parameters": [
+ {
+ "Name": "args",
+ "Type": "System.String[]"
+ }
+ ],
+ "ReturnType": "Microsoft.AspNetCore.Hosting.IWebHostBuilder",
+ "Static": true,
+ "Visibility": "Public",
+ "GenericParameter": []
+ }
+ ],
+ "GenericParameters": []
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/Metapackages/test/Directory.Build.props b/src/Metapackages/test/Directory.Build.props
new file mode 100644
index 0000000000..2a4205c758
--- /dev/null
+++ b/src/Metapackages/test/Directory.Build.props
@@ -0,0 +1,14 @@
+
+
+
+
+ netcoreapp2.1
+ $(DeveloperBuildTestTfms)
+ netcoreapp2.1;netcoreapp2.0
+ $(StandardTestTfms);net461
+
+
+
+
+
+
diff --git a/src/Metapackages/test/Microsoft.AspNetCore.FunctionalTests/Microsoft.AspNetCore.FunctionalTests.csproj b/src/Metapackages/test/Microsoft.AspNetCore.FunctionalTests/Microsoft.AspNetCore.FunctionalTests.csproj
new file mode 100644
index 0000000000..d4a5bbdf12
--- /dev/null
+++ b/src/Metapackages/test/Microsoft.AspNetCore.FunctionalTests/Microsoft.AspNetCore.FunctionalTests.csproj
@@ -0,0 +1,28 @@
+
+
+
+ $(StandardTestTfms)
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Metapackages/test/Microsoft.AspNetCore.FunctionalTests/WebHostFunctionalTests.cs b/src/Metapackages/test/Microsoft.AspNetCore.FunctionalTests/WebHostFunctionalTests.cs
new file mode 100644
index 0000000000..b882205779
--- /dev/null
+++ b/src/Metapackages/test/Microsoft.AspNetCore.FunctionalTests/WebHostFunctionalTests.cs
@@ -0,0 +1,238 @@
+// 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 System.Net.Http;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Hosting.Server.Features;
+using Microsoft.AspNetCore.Http;
+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 responseText = await response.Content.ReadAsStringAsync();
+ try
+ {
+ // Assert server is Kestrel
+ Assert.Equal("Kestrel", response.Headers.Server.ToString());
+ // Set from default config
+ Assert.Equal("http://localhost:5002/", deploymentResult.ApplicationBaseUri);
+ // The application name will be sent in response when all asserts succeed in the test app.
+ Assert.Equal(applicationName, responseText);
+ }
+ catch (XunitException)
+ {
+ logger.LogWarning(response.ToString());
+ logger.LogWarning(responseText);
+ throw;
+ }
+ }, setTestEnvVars: true);
+ }
+
+ [Fact]
+ public async Task CreateDefaultBuilderOfT_InitializeWithDefaults()
+ {
+ var applicationName = "CreateDefaultBuilderOfTApp";
+ await ExecuteTestApp(applicationName, async (deploymentResult, logger) =>
+ {
+ var response = await RetryHelper.RetryRequest(() => deploymentResult.HttpClient.GetAsync(string.Empty), logger, deploymentResult.HostShutdownToken);
+
+ var responseText = await response.Content.ReadAsStringAsync();
+ try
+ {
+ // Assert server is Kestrel
+ Assert.Equal("Kestrel", response.Headers.Server.ToString());
+ // Set from default config
+ Assert.Equal("http://localhost:5002/", deploymentResult.ApplicationBaseUri);
+ // The application name will be sent in response when all asserts succeed in the test app.
+ Assert.Equal(applicationName, responseText);
+ }
+ catch (XunitException)
+ {
+ logger.LogWarning(response.ToString());
+ logger.LogWarning(responseText);
+ throw;
+ }
+ }, setTestEnvVars: true);
+ }
+
+ [Theory]
+ [InlineData("Development", "InvalidOperationException: Cannot consume scoped service")]
+ [InlineData("Production", "Success")]
+ public async Task CreateDefaultBuilder_InitializesDependencyInjectionSettingsBasedOnEnv(string environment, string expected)
+ {
+ var applicationName = "DependencyInjectionApp";
+ await ExecuteTestApp(applicationName, async (deploymentResult, logger) =>
+ {
+ var response = await RetryHelper.RetryRequest(() => deploymentResult.HttpClient.GetAsync(string.Empty), logger, deploymentResult.HostShutdownToken);
+ var responseText = await response.Content.ReadAsStringAsync();
+ try
+ {
+ // Assert UseDeveloperExceptionPage is called in WebHostStartupFilter.
+ Assert.Contains(expected, responseText);
+ }
+ catch (XunitException)
+ {
+ logger.LogWarning(response.ToString());
+ logger.LogWarning(responseText);
+ throw;
+ }
+ }, setTestEnvVars: true, environment: environment);
+ }
+
+ [Fact]
+ public void LoggingConfigurationSectionPassedToLoggerByDefault()
+ {
+ try
+ {
+ File.WriteAllText("appsettings.json", @"
+{
+ ""Logging"": {
+ ""LogLevel"": {
+ ""Default"": ""Warning""
+ }
+ }
+}
+");
+ using (var webHost = WebHost.Start(context => context.Response.WriteAsync("Hello, World!")))
+ {
+ var factory = (ILoggerFactory)webHost.Services.GetService(typeof(ILoggerFactory));
+ var logger = factory.CreateLogger("Test");
+
+ logger.Log(LogLevel.Information, 0, "Message", null, (s, e) =>
+ {
+ Assert.True(false);
+ return string.Empty;
+ });
+
+ var logWritten = false;
+ logger.Log(LogLevel.Warning, 0, "Message", null, (s, e) =>
+ {
+ logWritten = true;
+ return string.Empty;
+ });
+
+ Assert.True(logWritten);
+ }
+ }
+ finally
+ {
+ File.Delete("appsettings.json");
+ }
+ }
+
+ 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,
+ string environment = "Development")
+ {
+ 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", environment));
+ 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}");
+ }
+
+ private static int GetWebHostPort(IWebHost webHost)
+ => webHost.ServerFeatures.Get().Addresses
+ .Select(serverAddress => new Uri(serverAddress).Port)
+ .FirstOrDefault();
+ }
+}
diff --git a/src/Metapackages/test/Microsoft.AspNetCore.FunctionalTests/testCert.pfx b/src/Metapackages/test/Microsoft.AspNetCore.FunctionalTests/testCert.pfx
new file mode 100644
index 0000000000..7118908c2d
Binary files /dev/null and b/src/Metapackages/test/Microsoft.AspNetCore.FunctionalTests/testCert.pfx differ
diff --git a/src/Metapackages/test/Microsoft.AspNetCore.Tests/Microsoft.AspNetCore.Tests.csproj b/src/Metapackages/test/Microsoft.AspNetCore.Tests/Microsoft.AspNetCore.Tests.csproj
new file mode 100644
index 0000000000..1b8156a1ca
--- /dev/null
+++ b/src/Metapackages/test/Microsoft.AspNetCore.Tests/Microsoft.AspNetCore.Tests.csproj
@@ -0,0 +1,18 @@
+
+
+
+ $(StandardTestTfms)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Metapackages/test/Microsoft.AspNetCore.Tests/WebHostTests.cs b/src/Metapackages/test/Microsoft.AspNetCore.Tests/WebHostTests.cs
new file mode 100644
index 0000000000..e076f0f19c
--- /dev/null
+++ b/src/Metapackages/test/Microsoft.AspNetCore.Tests/WebHostTests.cs
@@ -0,0 +1,69 @@
+// 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.HostFiltering;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using Xunit;
+
+namespace Microsoft.AspNetCore.Tests
+{
+ public class WebHostTests
+ {
+ [Fact]
+ public void WebHostConfiguration_IncludesCommandLineArguments()
+ {
+ var builder = WebHost.CreateDefaultBuilder(new string[] { "--urls", "http://localhost:5001" });
+ Assert.Equal("http://localhost:5001", builder.GetSetting(WebHostDefaults.ServerUrlsKey));
+ }
+
+ [Fact]
+ public void WebHostConfiguration_HostFilterOptionsAreReloadable()
+ {
+ var host = WebHost.CreateDefaultBuilder()
+ .Configure(app => { })
+ .ConfigureAppConfiguration(configBuilder =>
+ {
+ configBuilder.Add(new ReloadableMemorySource());
+ }).Build();
+ var config = host.Services.GetRequiredService();
+ var monitor = host.Services.GetRequiredService>();
+ var options = monitor.CurrentValue;
+
+ Assert.Contains("*", options.AllowedHosts);
+
+ var changed = new ManualResetEvent(false);
+ monitor.OnChange(newOptions =>
+ {
+ changed.Set();
+ });
+
+ config["AllowedHosts"] = "NewHost";
+
+ Assert.True(changed.WaitOne(TimeSpan.FromSeconds(10)));
+ options = monitor.CurrentValue;
+ Assert.Contains("NewHost", options.AllowedHosts);
+ }
+
+ private class ReloadableMemorySource : IConfigurationSource
+ {
+ public IConfigurationProvider Build(IConfigurationBuilder builder)
+ {
+ return new ReloadableMemoryProvider();
+ }
+ }
+
+ private class ReloadableMemoryProvider : ConfigurationProvider
+ {
+ public override void Set(string key, string value)
+ {
+ base.Set(key, value);
+ OnReload();
+ }
+ }
+ }
+}
diff --git a/src/Metapackages/test/TestSites/CreateDefaultBuilderApp/CreateDefaultBuilderApp.csproj b/src/Metapackages/test/TestSites/CreateDefaultBuilderApp/CreateDefaultBuilderApp.csproj
new file mode 100644
index 0000000000..7b43959e2f
--- /dev/null
+++ b/src/Metapackages/test/TestSites/CreateDefaultBuilderApp/CreateDefaultBuilderApp.csproj
@@ -0,0 +1,13 @@
+
+
+
+ Exe
+ netcoreapp2.0
+ aspnetcore-CreateDefaultBuilder-20170424224131
+
+
+
+
+
+
+
diff --git a/src/Metapackages/test/TestSites/CreateDefaultBuilderApp/Program.cs b/src/Metapackages/test/TestSites/CreateDefaultBuilderApp/Program.cs
new file mode 100644
index 0000000000..e8b91c67c0
--- /dev/null
+++ b/src/Metapackages/test/TestSites/CreateDefaultBuilderApp/Program.cs
@@ -0,0 +1,76 @@
+// 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.IO;
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace CreateDefaultBuilderApp
+{
+ public class Program
+ {
+ static void Main(string[] args)
+ {
+ string responseMessage = string.Empty;
+
+ WebHost.CreateDefaultBuilder(new[] { "--cliKey", "cliValue" })
+ .ConfigureServices((context, services) =>
+ {
+ responseMessage = GetResponseMessage(context, services);
+ })
+ .Configure(app =>
+ {
+ 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.";
+ }
+
+ // TODO: Verify AddConsole called
+ // TODO: Verify AddDebug called
+ // TODO: Verify UseIISIntegration called
+
+ return context.HostingEnvironment.ApplicationName;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Metapackages/test/TestSites/CreateDefaultBuilderApp/appsettings.Development.json b/src/Metapackages/test/TestSites/CreateDefaultBuilderApp/appsettings.Development.json
new file mode 100644
index 0000000000..d2ccc50d64
--- /dev/null
+++ b/src/Metapackages/test/TestSites/CreateDefaultBuilderApp/appsettings.Development.json
@@ -0,0 +1,3 @@
+{
+ "devSettingsKey": "devSettingsValue"
+}
diff --git a/src/Metapackages/test/TestSites/CreateDefaultBuilderApp/appsettings.json b/src/Metapackages/test/TestSites/CreateDefaultBuilderApp/appsettings.json
new file mode 100644
index 0000000000..393b080efb
--- /dev/null
+++ b/src/Metapackages/test/TestSites/CreateDefaultBuilderApp/appsettings.json
@@ -0,0 +1,10 @@
+{
+ "settingsKey": "settingsValue",
+ "Kestrel": {
+ "Endpoints": {
+ "HTTP": {
+ "Url": "http://localhost:5002"
+ }
+ }
+ }
+}
diff --git a/src/Metapackages/test/TestSites/CreateDefaultBuilderOfTApp/CreateDefaultBuilderOfTApp.csproj b/src/Metapackages/test/TestSites/CreateDefaultBuilderOfTApp/CreateDefaultBuilderOfTApp.csproj
new file mode 100644
index 0000000000..c73ee499ff
--- /dev/null
+++ b/src/Metapackages/test/TestSites/CreateDefaultBuilderOfTApp/CreateDefaultBuilderOfTApp.csproj
@@ -0,0 +1,13 @@
+
+
+
+ Exe
+ netcoreapp2.0
+ aspnetcore-CreateDefaultBuilderOfT-20170424224131
+
+
+
+
+
+
+
diff --git a/src/Metapackages/test/TestSites/CreateDefaultBuilderOfTApp/Program.cs b/src/Metapackages/test/TestSites/CreateDefaultBuilderOfTApp/Program.cs
new file mode 100644
index 0000000000..fbdc90efee
--- /dev/null
+++ b/src/Metapackages/test/TestSites/CreateDefaultBuilderOfTApp/Program.cs
@@ -0,0 +1,14 @@
+// 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 Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+
+namespace CreateDefaultBuilderOfTApp
+{
+ public class Program
+ {
+ static void Main(string[] args) => WebHost.CreateDefaultBuilder(new[] { "--cliKey", "cliValue" }) .Build().Run();
+ }
+}
\ No newline at end of file
diff --git a/src/Metapackages/test/TestSites/CreateDefaultBuilderOfTApp/Startup.cs b/src/Metapackages/test/TestSites/CreateDefaultBuilderOfTApp/Startup.cs
new file mode 100644
index 0000000000..2bfb0cdfe9
--- /dev/null
+++ b/src/Metapackages/test/TestSites/CreateDefaultBuilderOfTApp/Startup.cs
@@ -0,0 +1,74 @@
+// 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.IO;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.HostFiltering;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+
+namespace CreateDefaultBuilderOfTApp
+{
+ class Startup
+ {
+ public void Configure(IApplicationBuilder app, WebHostBuilderContext webHostBuilderContext)
+ {
+ app.Run(context =>
+ {
+ var message = GetResponseMessage(webHostBuilderContext, app.ApplicationServices.GetRequiredService>());
+ return context.Response.WriteAsync(message);
+ });
+ }
+
+ private static string GetResponseMessage(WebHostBuilderContext context, IOptions hostFilteringOptions)
+ {
+ // 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.";
+ }
+
+ // Verify allowed hosts were loaded
+ var hosts = string.Join(',', hostFilteringOptions.Value.AllowedHosts);
+ if (!string.Equals("example.com,localhost", hosts, StringComparison.Ordinal))
+ {
+ return $"AllowedHosts not loaded into Options.";
+ }
+
+ // TODO: Verify AddConsole called
+ // TODO: Verify AddDebug called
+ // TODO: Verify UseIISIntegration called
+
+ return context.HostingEnvironment.ApplicationName;
+ }
+ }
+}
diff --git a/src/Metapackages/test/TestSites/CreateDefaultBuilderOfTApp/appsettings.Development.json b/src/Metapackages/test/TestSites/CreateDefaultBuilderOfTApp/appsettings.Development.json
new file mode 100644
index 0000000000..d2ccc50d64
--- /dev/null
+++ b/src/Metapackages/test/TestSites/CreateDefaultBuilderOfTApp/appsettings.Development.json
@@ -0,0 +1,3 @@
+{
+ "devSettingsKey": "devSettingsValue"
+}
diff --git a/src/Metapackages/test/TestSites/CreateDefaultBuilderOfTApp/appsettings.json b/src/Metapackages/test/TestSites/CreateDefaultBuilderOfTApp/appsettings.json
new file mode 100644
index 0000000000..27eb1aaf44
--- /dev/null
+++ b/src/Metapackages/test/TestSites/CreateDefaultBuilderOfTApp/appsettings.json
@@ -0,0 +1,11 @@
+{
+ "settingsKey": "settingsValue",
+ "AllowedHosts": "example.com;localhost",
+ "Kestrel": {
+ "Endpoints": {
+ "HTTP": {
+ "Url": "http://localhost:5002"
+ }
+ }
+ }
+}
diff --git a/src/Metapackages/test/TestSites/DependencyInjectionApp/DependencyInjectionApp.csproj b/src/Metapackages/test/TestSites/DependencyInjectionApp/DependencyInjectionApp.csproj
new file mode 100644
index 0000000000..7930c4a822
--- /dev/null
+++ b/src/Metapackages/test/TestSites/DependencyInjectionApp/DependencyInjectionApp.csproj
@@ -0,0 +1,12 @@
+
+
+
+ Exe
+ netcoreapp2.0
+
+
+
+
+
+
+
diff --git a/src/Metapackages/test/TestSites/DependencyInjectionApp/Program.cs b/src/Metapackages/test/TestSites/DependencyInjectionApp/Program.cs
new file mode 100644
index 0000000000..6e4850002b
--- /dev/null
+++ b/src/Metapackages/test/TestSites/DependencyInjectionApp/Program.cs
@@ -0,0 +1,68 @@
+// 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)
+ {
+ WebHost.CreateDefaultBuilder()
+ .UseUrls("http://localhost:5002")
+ .ConfigureServices((context, services) =>
+ {
+ services.AddSingleton(typeof(IService<>), typeof(Service<>));
+ services.AddScoped();
+ })
+ .Configure(app =>
+ {
+ app.Run(context =>
+ {
+ try
+ {
+ context.RequestServices.GetService>();
+ return context.Response.WriteAsync("Success");
+ }
+ catch (Exception ex)
+ {
+ return context.Response.WriteAsync(ex.ToString());
+ }
+ });
+ })
+ .Build().Run();
+ }
+
+ interface IService
+ {
+ }
+
+ interface IAnotherService
+ {
+ }
+
+ class Service: IService
+ {
+ public Service(T t)
+ {
+ }
+ }
+
+ class AnotherService: IAnotherService
+ {
+ }
+ }
+}
diff --git a/src/Metapackages/test/TestSites/StartRequestDelegateUrlApp/Program.cs b/src/Metapackages/test/TestSites/StartRequestDelegateUrlApp/Program.cs
new file mode 100644
index 0000000000..351f870b56
--- /dev/null
+++ b/src/Metapackages/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/src/Metapackages/test/TestSites/StartRequestDelegateUrlApp/StartRequestDelegateUrlApp.csproj b/src/Metapackages/test/TestSites/StartRequestDelegateUrlApp/StartRequestDelegateUrlApp.csproj
new file mode 100644
index 0000000000..7930c4a822
--- /dev/null
+++ b/src/Metapackages/test/TestSites/StartRequestDelegateUrlApp/StartRequestDelegateUrlApp.csproj
@@ -0,0 +1,12 @@
+
+
+
+ Exe
+ netcoreapp2.0
+
+
+
+
+
+
+
diff --git a/src/Metapackages/test/TestSites/StartRouteBuilderUrlApp/Program.cs b/src/Metapackages/test/TestSites/StartRouteBuilderUrlApp/Program.cs
new file mode 100644
index 0000000000..5aa13ea396
--- /dev/null
+++ b/src/Metapackages/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/src/Metapackages/test/TestSites/StartRouteBuilderUrlApp/StartRouteBuilderUrlApp.csproj b/src/Metapackages/test/TestSites/StartRouteBuilderUrlApp/StartRouteBuilderUrlApp.csproj
new file mode 100644
index 0000000000..7930c4a822
--- /dev/null
+++ b/src/Metapackages/test/TestSites/StartRouteBuilderUrlApp/StartRouteBuilderUrlApp.csproj
@@ -0,0 +1,12 @@
+
+
+
+ Exe
+ netcoreapp2.0
+
+
+
+
+
+
+
diff --git a/src/Metapackages/test/TestSites/StartWithIApplicationBuilderUrlApp/Program.cs b/src/Metapackages/test/TestSites/StartWithIApplicationBuilderUrlApp/Program.cs
new file mode 100644
index 0000000000..f904dcff57
--- /dev/null
+++ b/src/Metapackages/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/src/Metapackages/test/TestSites/StartWithIApplicationBuilderUrlApp/StartWithIApplicationBuilderUrlApp.csproj b/src/Metapackages/test/TestSites/StartWithIApplicationBuilderUrlApp/StartWithIApplicationBuilderUrlApp.csproj
new file mode 100644
index 0000000000..7930c4a822
--- /dev/null
+++ b/src/Metapackages/test/TestSites/StartWithIApplicationBuilderUrlApp/StartWithIApplicationBuilderUrlApp.csproj
@@ -0,0 +1,12 @@
+
+
+
+ Exe
+ netcoreapp2.0
+
+
+
+
+
+
+
diff --git a/src/Metapackages/version.props b/src/Metapackages/version.props
new file mode 100644
index 0000000000..c5a1f7a6cf
--- /dev/null
+++ b/src/Metapackages/version.props
@@ -0,0 +1,12 @@
+
+
+ 2.1.7
+ servicing
+ $(VersionPrefix)
+ $(VersionPrefix)-$(VersionSuffix)-final
+ t000
+ a-
+ $(FeatureBranchVersionPrefix)$(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-'))
+ $(VersionSuffix)-$(BuildNumber)
+
+