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