diff --git a/src/AzureIntegration/.gitignore b/src/AzureIntegration/.gitignore new file mode 100644 index 0000000000..5c05ff5f40 --- /dev/null +++ b/src/AzureIntegration/.gitignore @@ -0,0 +1,34 @@ +[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 +.build/ +.testPublish/ +global.json +msbuild.binlog +.test-dotnet/ +.deps/ \ No newline at end of file diff --git a/src/AzureIntegration/AzureIntegration.sln b/src/AzureIntegration/AzureIntegration.sln new file mode 100644 index 0000000000..cc9ac83c23 --- /dev/null +++ b/src/AzureIntegration/AzureIntegration.sln @@ -0,0 +1,117 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27016.1 +MinimumVisualStudioVersion = 15.0.26730.03 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.AzureAppServicesIntegration", "src\Microsoft.AspNetCore.AzureAppServicesIntegration\Microsoft.AspNetCore.AzureAppServicesIntegration.csproj", "{5916BEB5-0969-469B-976C-A392E015DFAC}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{FF9B744E-6C59-40CC-9E41-9D2EBD292435}" + ProjectSection(SolutionItems) = preProject + src\Directory.Build.props = src\Directory.Build.props + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2FFE2B87-BF8A-4B38-ADAB-2FE2F9BC4A7C}" + ProjectSection(SolutionItems) = preProject + build\dependencies.props = build\dependencies.props + Directory.Build.props = Directory.Build.props + Directory.Build.targets = Directory.Build.targets + NuGet.config = NuGet.config + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureAppServicesSample", "sample\AzureAppServicesSample\AzureAppServicesSample.csproj", "{05A4D308-B162-4194-BC5E-88CCB4DBD318}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{37237C93-6855-40D9-9E60-418B093EF49A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{CD650B4B-81C2-4A44-AEF2-A251A877C1F0}" + ProjectSection(SolutionItems) = preProject + test\Directory.Build.props = test\Directory.Build.props + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.AzureAppServicesIntegration.Tests", "test\Microsoft.AspNetCore.AzureAppServicesIntegration.Tests\Microsoft.AspNetCore.AzureAppServicesIntegration.Tests.csproj", "{9BA1B692-B313-4E22-A864-F0ADBBE3C3FA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.AzureAppServices.HostingStartup", "src\Microsoft.AspNetCore.AzureAppServices.HostingStartup\Microsoft.AspNetCore.AzureAppServices.HostingStartup.csproj", "{AC023B45-7995-4D4A-8108-E512AE8E5734}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureAppServicesHostingStartupSample", "sample\AzureAppServicesHostingStartupSample\AzureAppServicesHostingStartupSample.csproj", "{939EA897-CA31-4F2E-BA51-22B570B64671}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Web.Xdt.Extensions", "src\Microsoft.Web.Xdt.Extensions\Microsoft.Web.Xdt.Extensions.csproj", "{9B22E525-FEC9-4C7C-9F9C-598C15BD0250}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.AzureAppServices.SiteExtension", "extensions\Microsoft.AspNetCore.AzureAppServices.SiteExtension\Microsoft.AspNetCore.AzureAppServices.SiteExtension.csproj", "{1CE2D76B-39E6-46C0-8F6F-C63E370955A9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Web.Xdt.Extensions.Tests", "test\Microsoft.Web.Xdt.Extensions.Tests\Microsoft.Web.Xdt.Extensions.Tests.csproj", "{809AEE05-1B28-4E31-8959-776B249BD725}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.ApplicationModelDetection", "src\Microsoft.Extensions.ApplicationModelDetection\Microsoft.Extensions.ApplicationModelDetection.csproj", "{F0CABFE8-A5B1-487B-A451-A486D26742D3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.ApplicationModelDetection.Tests", "test\Microsoft.Extensions.ApplicationModelDetection.Tests\Microsoft.Extensions.ApplicationModelDetection.Tests.csproj", "{15664836-2B94-4D2D-AC18-6DED01FCCCBD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Runtime.SiteExtension", "extensions\Microsoft.AspNetCore.Runtime.SiteExtension\Microsoft.AspNetCore.Runtime.SiteExtension.csproj", "{E1E9BC7A-6951-4B60-8DFB-DBB9AC3CDEB0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5916BEB5-0969-469B-976C-A392E015DFAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5916BEB5-0969-469B-976C-A392E015DFAC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5916BEB5-0969-469B-976C-A392E015DFAC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5916BEB5-0969-469B-976C-A392E015DFAC}.Release|Any CPU.Build.0 = Release|Any CPU + {05A4D308-B162-4194-BC5E-88CCB4DBD318}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {05A4D308-B162-4194-BC5E-88CCB4DBD318}.Debug|Any CPU.Build.0 = Debug|Any CPU + {05A4D308-B162-4194-BC5E-88CCB4DBD318}.Release|Any CPU.ActiveCfg = Release|Any CPU + {05A4D308-B162-4194-BC5E-88CCB4DBD318}.Release|Any CPU.Build.0 = Release|Any CPU + {9BA1B692-B313-4E22-A864-F0ADBBE3C3FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9BA1B692-B313-4E22-A864-F0ADBBE3C3FA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9BA1B692-B313-4E22-A864-F0ADBBE3C3FA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9BA1B692-B313-4E22-A864-F0ADBBE3C3FA}.Release|Any CPU.Build.0 = Release|Any CPU + {AC023B45-7995-4D4A-8108-E512AE8E5734}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AC023B45-7995-4D4A-8108-E512AE8E5734}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AC023B45-7995-4D4A-8108-E512AE8E5734}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AC023B45-7995-4D4A-8108-E512AE8E5734}.Release|Any CPU.Build.0 = Release|Any CPU + {939EA897-CA31-4F2E-BA51-22B570B64671}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {939EA897-CA31-4F2E-BA51-22B570B64671}.Debug|Any CPU.Build.0 = Debug|Any CPU + {939EA897-CA31-4F2E-BA51-22B570B64671}.Release|Any CPU.ActiveCfg = Release|Any CPU + {939EA897-CA31-4F2E-BA51-22B570B64671}.Release|Any CPU.Build.0 = Release|Any CPU + {9B22E525-FEC9-4C7C-9F9C-598C15BD0250}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9B22E525-FEC9-4C7C-9F9C-598C15BD0250}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9B22E525-FEC9-4C7C-9F9C-598C15BD0250}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9B22E525-FEC9-4C7C-9F9C-598C15BD0250}.Release|Any CPU.Build.0 = Release|Any CPU + {1CE2D76B-39E6-46C0-8F6F-C63E370955A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1CE2D76B-39E6-46C0-8F6F-C63E370955A9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1CE2D76B-39E6-46C0-8F6F-C63E370955A9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1CE2D76B-39E6-46C0-8F6F-C63E370955A9}.Release|Any CPU.Build.0 = Release|Any CPU + {809AEE05-1B28-4E31-8959-776B249BD725}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {809AEE05-1B28-4E31-8959-776B249BD725}.Debug|Any CPU.Build.0 = Debug|Any CPU + {809AEE05-1B28-4E31-8959-776B249BD725}.Release|Any CPU.ActiveCfg = Release|Any CPU + {809AEE05-1B28-4E31-8959-776B249BD725}.Release|Any CPU.Build.0 = Release|Any CPU + {F0CABFE8-A5B1-487B-A451-A486D26742D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F0CABFE8-A5B1-487B-A451-A486D26742D3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F0CABFE8-A5B1-487B-A451-A486D26742D3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F0CABFE8-A5B1-487B-A451-A486D26742D3}.Release|Any CPU.Build.0 = Release|Any CPU + {15664836-2B94-4D2D-AC18-6DED01FCCCBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {15664836-2B94-4D2D-AC18-6DED01FCCCBD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {15664836-2B94-4D2D-AC18-6DED01FCCCBD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {15664836-2B94-4D2D-AC18-6DED01FCCCBD}.Release|Any CPU.Build.0 = Release|Any CPU + {E1E9BC7A-6951-4B60-8DFB-DBB9AC3CDEB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E1E9BC7A-6951-4B60-8DFB-DBB9AC3CDEB0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E1E9BC7A-6951-4B60-8DFB-DBB9AC3CDEB0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E1E9BC7A-6951-4B60-8DFB-DBB9AC3CDEB0}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {5916BEB5-0969-469B-976C-A392E015DFAC} = {FF9B744E-6C59-40CC-9E41-9D2EBD292435} + {05A4D308-B162-4194-BC5E-88CCB4DBD318} = {37237C93-6855-40D9-9E60-418B093EF49A} + {9BA1B692-B313-4E22-A864-F0ADBBE3C3FA} = {CD650B4B-81C2-4A44-AEF2-A251A877C1F0} + {AC023B45-7995-4D4A-8108-E512AE8E5734} = {FF9B744E-6C59-40CC-9E41-9D2EBD292435} + {939EA897-CA31-4F2E-BA51-22B570B64671} = {37237C93-6855-40D9-9E60-418B093EF49A} + {9B22E525-FEC9-4C7C-9F9C-598C15BD0250} = {FF9B744E-6C59-40CC-9E41-9D2EBD292435} + {1CE2D76B-39E6-46C0-8F6F-C63E370955A9} = {FF9B744E-6C59-40CC-9E41-9D2EBD292435} + {809AEE05-1B28-4E31-8959-776B249BD725} = {CD650B4B-81C2-4A44-AEF2-A251A877C1F0} + {F0CABFE8-A5B1-487B-A451-A486D26742D3} = {FF9B744E-6C59-40CC-9E41-9D2EBD292435} + {15664836-2B94-4D2D-AC18-6DED01FCCCBD} = {CD650B4B-81C2-4A44-AEF2-A251A877C1F0} + {E1E9BC7A-6951-4B60-8DFB-DBB9AC3CDEB0} = {FF9B744E-6C59-40CC-9E41-9D2EBD292435} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {5743DFE7-1AA5-439D-84AE-A480EA389927} + EndGlobalSection +EndGlobal diff --git a/src/AzureIntegration/Directory.Build.props b/src/AzureIntegration/Directory.Build.props new file mode 100644 index 0000000000..dcab7b1a0f --- /dev/null +++ b/src/AzureIntegration/Directory.Build.props @@ -0,0 +1,20 @@ + + + + + + + + + Microsoft ASP.NET Core + https://github.com/aspnet/AzureIntegration + git + $(MSBuildThisFileDirectory) + $(MSBuildThisFileDirectory)build\Key.snk + true + true + + + diff --git a/src/AzureIntegration/Directory.Build.targets b/src/AzureIntegration/Directory.Build.targets new file mode 100644 index 0000000000..7e3f8df92e --- /dev/null +++ b/src/AzureIntegration/Directory.Build.targets @@ -0,0 +1,6 @@ + + + $(MicrosoftNETCoreAppPackageVersion) + $(NETStandardLibrary20PackageVersion) + + diff --git a/src/AzureIntegration/NuGetPackageVerifier.json b/src/AzureIntegration/NuGetPackageVerifier.json new file mode 100644 index 0000000000..cf7178529c --- /dev/null +++ b/src/AzureIntegration/NuGetPackageVerifier.json @@ -0,0 +1,16 @@ +{ + "adx": { // Packages written by the ADX team and that ship on NuGet.org + "rules": [ + "AdxVerificationCompositeRule" + ], + "packages": { + "Microsoft.AspNetCore.AzureAppServicesIntegration": { }, + "Microsoft.Extensions.ApplicationModelDetection": { } + } + }, + "Default": { // Rules to run for packages not listed in any other set. + "rules": [ + "DefaultCompositeRule" + ] + } +} \ No newline at end of file diff --git a/src/AzureIntegration/README.md b/src/AzureIntegration/README.md new file mode 100644 index 0000000000..1eeece66ef --- /dev/null +++ b/src/AzureIntegration/README.md @@ -0,0 +1,27 @@ +AzureIntegration +=== + +Features that integrate ASP.NET Core with Azure. + +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. + + +SiteExtensions +=== + +To install a nightly preview of the ASP.NET Core runtime site extension for testing purposes: +1. In the Azure portal select App Services -> your site -> Application settings +1. Set `SCM_SITEEXTENSIONS_FEED_URL` application setting to `https://dotnet.myget.org/F/aspnetcore-dev/` +1. Go to `DEVELOPMENT TOOLS` -> `Advanced Tools` -> `Site extensions` -> `Gallery` +1. Enter `AspNetCoreRuntime` into `Search` box and click `Search` +1. Click `+` to install site extension and wait untill installation animation finishes +1. `Extensions` tab should now show newly installed site extension +1. Click `Restart site` on the right side of the page when installation finishes (this would only restart Kudu site, not the main one) +1. Restart site in `Overview` tab of `App service` + + +To update ASP.NET Core runtime site extension: +1. Stop site in `Overview` tab of `App service` +1. Go to `DEVELOPMENT TOOLS` -> `Advanced Tools` -> `Site extensions` +1. Click update on site extension +1. Start site in `Overview` tab of `App service` \ No newline at end of file diff --git a/src/AzureIntegration/build/Key.snk b/src/AzureIntegration/build/Key.snk new file mode 100644 index 0000000000..e10e4889c1 Binary files /dev/null and b/src/AzureIntegration/build/Key.snk differ diff --git a/src/AzureIntegration/build/dependencies.props b/src/AzureIntegration/build/dependencies.props new file mode 100644 index 0000000000..3c2678cb58 --- /dev/null +++ b/src/AzureIntegration/build/dependencies.props @@ -0,0 +1,47 @@ + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + + + 3.0.0-build-20181114.5 + 3.0.0-build-20181114.5 + 3.0.0-alpha1-10742 + 3.0.0-alpha1-10742 + 3.0.0-alpha1-10742 + 3.0.0-alpha1-10742 + 3.0.0-alpha1-10742 + 3.0.0-alpha1-10742 + 3.0.0-alpha1-10742 + 3.0.0-alpha1-10742 + 3.0.0-alpha1-10742 + 0.7.0-alpha1-10742 + 3.0.0-alpha1-10742 + 3.0.0-alpha1-10742 + 1.1.3 + 1.0.3 + 3.0.0-alpha1-10670 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview1-26907-05 + 3.0.0-alpha1-10742 + 15.6.1 + 1.4.0 + 4.10.0 + 2.0.3 + 11.0.2 + 1.7.0-preview1-26907-04 + 8.1.4 + 2.3.1 + 2.4.0 + + + + diff --git a/src/AzureIntegration/build/hostingstartup.targets b/src/AzureIntegration/build/hostingstartup.targets new file mode 100644 index 0000000000..2e8dd15047 --- /dev/null +++ b/src/AzureIntegration/build/hostingstartup.targets @@ -0,0 +1,11 @@ + + + + <_PackageFiles Include="$(ProjectDepsFilePath)"> + lib\$(TargetFramework) + false + Content + + + + diff --git a/src/AzureIntegration/build/repo.props b/src/AzureIntegration/build/repo.props new file mode 100644 index 0000000000..a8505ea0f4 --- /dev/null +++ b/src/AzureIntegration/build/repo.props @@ -0,0 +1,35 @@ + + + + + $(RepositoryRoot)test\Microsoft.AspNetCore.AzureAppServices.FunctionalTests\Microsoft.AspNetCore.AzureAppServices.FunctionalTests.csproj + + + Internal.AspNetCore.Universe.Lineup + https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json + + + + + + + + + + + + + + + + + + + + + diff --git a/src/AzureIntegration/build/repo.targets b/src/AzureIntegration/build/repo.targets new file mode 100644 index 0000000000..199837a956 --- /dev/null +++ b/src/AzureIntegration/build/repo.targets @@ -0,0 +1,94 @@ + + + + True + <_SdkVersion>$(SITE_EXTENSION_SDK_VERSION) + <_SdkVersion Condition="'$(_SdkVersion)' == ''">$([System.IO.Path]::GetFileName($([System.IO.Path]::GetDirectoryName('$(MSBuildExtensionsPath)')))) + <_SdkFeed>$(SITE_EXTENSION_SDK_FEED) + <_SdkFeed Condition="'$(_SdkFeed)' == ''">$(DefaultDotNetAssetFeed) + $(RepositoryRoot).test-dotnet\ + $(RepositoryRoot)artifacts\apps + $(TestDotNetPath)extension\$(SiteExtensionArch)\ + $(RepositoryRoot)artifacts\build + $(RepositoryRoot)\test\Microsoft.AspNetCore.AzureAppServices.FunctionalTests\ + https://dotnet.myget.org/F/aspnetcore-dev/ + $(MicrosoftNETCoreAppPackageVersion) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/AzureIntegration/build/sources.props b/src/AzureIntegration/build/sources.props new file mode 100644 index 0000000000..9215df9751 --- /dev/null +++ b/src/AzureIntegration/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/AzureIntegration/extensions/Directory.Build.props b/src/AzureIntegration/extensions/Directory.Build.props new file mode 100644 index 0000000000..d333f1a2b7 --- /dev/null +++ b/src/AzureIntegration/extensions/Directory.Build.props @@ -0,0 +1,23 @@ + + + + net461 + false + AzureSiteExtension + true + false + false + false + content + + $(NoWarn);NU5119 + + + + + + diff --git a/src/AzureIntegration/extensions/Microsoft.AspNetCore.AzureAppServices.SiteExtension/Microsoft.AspNetCore.AzureAppServices.SiteExtension.csproj b/src/AzureIntegration/extensions/Microsoft.AspNetCore.AzureAppServices.SiteExtension/Microsoft.AspNetCore.AzureAppServices.SiteExtension.csproj new file mode 100644 index 0000000000..00f21b9bae --- /dev/null +++ b/src/AzureIntegration/extensions/Microsoft.AspNetCore.AzureAppServices.SiteExtension/Microsoft.AspNetCore.AzureAppServices.SiteExtension.csproj @@ -0,0 +1,21 @@ + + + + $(VersionPrefix.Substring(0, $(VersionPrefix.LastIndexOf('.')))) + ASP.NET Core Extensions + This extension enables additional functionality for ASP.NET Core on Azure WebSites, such as enabling Azure logging. + netcoreapp3.0 + false + aspnet;logging;aspnetcore;AzureSiteExtension;keyvault;configuration;dataprotection + content + $(MicrosoftNETCoreAppPackageVersion) + Microsoft.AspNetCore.AzureAppServices.SiteExtension.$(TrimmedVersion) + + + + + + + + + diff --git a/src/AzureIntegration/extensions/Microsoft.AspNetCore.Runtime.SiteExtension/Microsoft.AspNetCore.Runtime.SiteExtension.csproj b/src/AzureIntegration/extensions/Microsoft.AspNetCore.Runtime.SiteExtension/Microsoft.AspNetCore.Runtime.SiteExtension.csproj new file mode 100644 index 0000000000..6ff0419a6f --- /dev/null +++ b/src/AzureIntegration/extensions/Microsoft.AspNetCore.Runtime.SiteExtension/Microsoft.AspNetCore.Runtime.SiteExtension.csproj @@ -0,0 +1,36 @@ + + + + $(VersionPrefix.Substring(0, $(VersionPrefix.LastIndexOf('.')))) + ASP.NET Core $(TrimmedVersion) ($(RuntimeArch)) Runtime + This site extension installs Microsoft.AspNetCore.All, Microsoft.AspNetCore.App and Microsoft.NetCore.App shared runtimes. + aspnetcore;AzureSiteExtension + AspNetCoreRuntime.$(TrimmedVersion).$(RuntimeArch) + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/AzureIntegration/extensions/Microsoft.AspNetCore.Runtime.SiteExtension/applicationHost.xdt b/src/AzureIntegration/extensions/Microsoft.AspNetCore.Runtime.SiteExtension/applicationHost.xdt new file mode 100644 index 0000000000..159bc8d646 --- /dev/null +++ b/src/AzureIntegration/extensions/Microsoft.AspNetCore.Runtime.SiteExtension/applicationHost.xdt @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/AzureIntegration/extensions/Microsoft.AspNetCore.Runtime.SiteExtension/install.cmd b/src/AzureIntegration/extensions/Microsoft.AspNetCore.Runtime.SiteExtension/install.cmd new file mode 100644 index 0000000000..bdca3efa75 --- /dev/null +++ b/src/AzureIntegration/extensions/Microsoft.AspNetCore.Runtime.SiteExtension/install.cmd @@ -0,0 +1,16 @@ +FOR /R %%x IN (*.nupkg_) DO REN "%%x" "*.nupkg" + + +SET DOTNET=D:\Program Files (x86)\dotnet +SET RUNTIMES=%DOTNET%\shared\Microsoft.NETCore.App + +IF "%ASPNETCORE_COPY_EXISTING_RUNTIMES%" NEQ "1" EXIT /b 0 + +robocopy "%DOTNET%" "." /E /XC /XN /XO /NFL /NDL ^ + /XD "%DOTNET%\sdk" ^ + /XD "%RUNTIMES%\1.0.8" ^ + /XD "%RUNTIMES%\1.1.5" ^ + /XD "%RUNTIMES%\2.0.3" + +IF %errorlevel% geq 8 EXIT /b 1 +EXIT /b 0 \ No newline at end of file diff --git a/src/AzureIntegration/extensions/Microsoft.AspNetCore.Runtime.SiteExtension/scmApplicationHost.xdt b/src/AzureIntegration/extensions/Microsoft.AspNetCore.Runtime.SiteExtension/scmApplicationHost.xdt new file mode 100644 index 0000000000..a8dd367f9f --- /dev/null +++ b/src/AzureIntegration/extensions/Microsoft.AspNetCore.Runtime.SiteExtension/scmApplicationHost.xdt @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/src/AzureIntegration/sample/AzureAppServicesHostingStartupSample/AzureAppServicesHostingStartupSample.csproj b/src/AzureIntegration/sample/AzureAppServicesHostingStartupSample/AzureAppServicesHostingStartupSample.csproj new file mode 100644 index 0000000000..a2f447ed5e --- /dev/null +++ b/src/AzureIntegration/sample/AzureAppServicesHostingStartupSample/AzureAppServicesHostingStartupSample.csproj @@ -0,0 +1,18 @@ + + + + netcoreapp3.0 + + + + + + + + + + + + + + diff --git a/src/AzureIntegration/sample/AzureAppServicesHostingStartupSample/Properties/launchSettings.json b/src/AzureIntegration/sample/AzureAppServicesHostingStartupSample/Properties/launchSettings.json new file mode 100644 index 0000000000..731d8620e9 --- /dev/null +++ b/src/AzureIntegration/sample/AzureAppServicesHostingStartupSample/Properties/launchSettings.json @@ -0,0 +1,24 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:22071/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.AzureAppServices.HostingStartup;Microsoft.AspNetCore.Server.IISIntegration" + } + }, + "AzureAppServicesHostingStartupSample": { + "commandName": "IISExpress", + "launchBrowser": true + } + } +} \ No newline at end of file diff --git a/src/AzureIntegration/sample/AzureAppServicesHostingStartupSample/Startup.cs b/src/AzureIntegration/sample/AzureAppServicesHostingStartupSample/Startup.cs new file mode 100644 index 0000000000..1a91822bc1 --- /dev/null +++ b/src/AzureIntegration/sample/AzureAppServicesHostingStartupSample/Startup.cs @@ -0,0 +1,76 @@ +using System; +using System.Linq; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; + +namespace IISSample +{ + public class Startup + { + public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) + { + var logger = loggerfactory.CreateLogger("Requests"); + + app.Run(async (context) => + { + logger.LogDebug("Received request: " + context.Request.Method + " " + context.Request.Path); + + context.Response.ContentType = "text/plain"; + await context.Response.WriteAsync("Hello World - " + DateTimeOffset.Now + Environment.NewLine); + await context.Response.WriteAsync(Environment.NewLine); + + await context.Response.WriteAsync("Address:" + Environment.NewLine); + await context.Response.WriteAsync("Scheme: " + context.Request.Scheme + Environment.NewLine); + await context.Response.WriteAsync("Host: " + context.Request.Headers["Host"] + Environment.NewLine); + await context.Response.WriteAsync("PathBase: " + context.Request.PathBase.Value + Environment.NewLine); + await context.Response.WriteAsync("Path: " + context.Request.Path.Value + Environment.NewLine); + await context.Response.WriteAsync("Query: " + context.Request.QueryString.Value + Environment.NewLine); + await context.Response.WriteAsync(Environment.NewLine); + + await context.Response.WriteAsync("Connection:" + Environment.NewLine); + await context.Response.WriteAsync("RemoteIp: " + context.Connection.RemoteIpAddress + Environment.NewLine); + await context.Response.WriteAsync("RemotePort: " + context.Connection.RemotePort + Environment.NewLine); + await context.Response.WriteAsync("LocalIp: " + context.Connection.LocalIpAddress + Environment.NewLine); + await context.Response.WriteAsync("LocalPort: " + context.Connection.LocalPort + Environment.NewLine); + await context.Response.WriteAsync("ClientCert: " + context.Connection.ClientCertificate + Environment.NewLine); + await context.Response.WriteAsync(Environment.NewLine); + + await context.Response.WriteAsync("User: " + context.User.Identity.Name + Environment.NewLine); + await context.Response.WriteAsync(Environment.NewLine); + + await context.Response.WriteAsync("Headers:" + Environment.NewLine); + foreach (var header in context.Request.Headers) + { + await context.Response.WriteAsync(header.Key + ": " + header.Value + Environment.NewLine); + } + await context.Response.WriteAsync(Environment.NewLine); + + await context.Response.WriteAsync("Environment Variables:" + Environment.NewLine); + var vars = Environment.GetEnvironmentVariables(); + foreach (var key in vars.Keys.Cast().OrderBy(key => key, StringComparer.OrdinalIgnoreCase)) + { + var value = vars[key]; + await context.Response.WriteAsync(key + ": " + value + Environment.NewLine); + } + await context.Response.WriteAsync(Environment.NewLine); + }); + } + + public static void Main(string[] args) + { + var host = new WebHostBuilder() + .ConfigureLogging(factory => + { + factory.AddConsole(); + }) + .UseKestrel() + .UseStartup() + .Build(); + + host.Run(); + } + } +} + diff --git a/src/AzureIntegration/sample/AzureAppServicesSample/AzureAppServicesSample.csproj b/src/AzureIntegration/sample/AzureAppServicesSample/AzureAppServicesSample.csproj new file mode 100644 index 0000000000..4b03ef5612 --- /dev/null +++ b/src/AzureIntegration/sample/AzureAppServicesSample/AzureAppServicesSample.csproj @@ -0,0 +1,18 @@ + + + + netcoreapp3.0 + + + + + + + + + + + + + + diff --git a/src/AzureIntegration/sample/AzureAppServicesSample/Properties/launchSettings.json b/src/AzureIntegration/sample/AzureAppServicesSample/Properties/launchSettings.json new file mode 100644 index 0000000000..93ebc1db03 --- /dev/null +++ b/src/AzureIntegration/sample/AzureAppServicesSample/Properties/launchSettings.json @@ -0,0 +1,24 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:64358/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.Server.IISIntegration" + } + }, + "AzureAppServicesSample": { + "commandName": "IISExpress", + "launchBrowser": true + } + } +} \ No newline at end of file diff --git a/src/AzureIntegration/sample/AzureAppServicesSample/Startup.cs b/src/AzureIntegration/sample/AzureAppServicesSample/Startup.cs new file mode 100644 index 0000000000..4638758d90 --- /dev/null +++ b/src/AzureIntegration/sample/AzureAppServicesSample/Startup.cs @@ -0,0 +1,89 @@ +using System; +using System.Linq; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace IISSample +{ + public class Startup + { + public void ConfigureServices(IServiceCollection services) + { + // These two middleware are registered via an IStartupFilter in UseIISIntegration but you can configure them here. + services.Configure(options => + { + }); + services.Configure(options => + { + }); + } + + public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) + { + var logger = loggerfactory.CreateLogger("Requests"); + + app.Run(async (context) => + { + logger.LogDebug("Received request: " + context.Request.Method + " " + context.Request.Path); + + context.Response.ContentType = "text/plain"; + await context.Response.WriteAsync("Hello World - " + DateTimeOffset.Now + Environment.NewLine); + await context.Response.WriteAsync(Environment.NewLine); + + await context.Response.WriteAsync("Address:" + Environment.NewLine); + await context.Response.WriteAsync("Scheme: " + context.Request.Scheme + Environment.NewLine); + await context.Response.WriteAsync("Host: " + context.Request.Headers["Host"] + Environment.NewLine); + await context.Response.WriteAsync("PathBase: " + context.Request.PathBase.Value + Environment.NewLine); + await context.Response.WriteAsync("Path: " + context.Request.Path.Value + Environment.NewLine); + await context.Response.WriteAsync("Query: " + context.Request.QueryString.Value + Environment.NewLine); + await context.Response.WriteAsync(Environment.NewLine); + + await context.Response.WriteAsync("Connection:" + Environment.NewLine); + await context.Response.WriteAsync("RemoteIp: " + context.Connection.RemoteIpAddress + Environment.NewLine); + await context.Response.WriteAsync("RemotePort: " + context.Connection.RemotePort + Environment.NewLine); + await context.Response.WriteAsync("LocalIp: " + context.Connection.LocalIpAddress + Environment.NewLine); + await context.Response.WriteAsync("LocalPort: " + context.Connection.LocalPort + Environment.NewLine); + await context.Response.WriteAsync("ClientCert: " + context.Connection.ClientCertificate + Environment.NewLine); + await context.Response.WriteAsync(Environment.NewLine); + + await context.Response.WriteAsync("User: " + context.User.Identity.Name + Environment.NewLine); + await context.Response.WriteAsync(Environment.NewLine); + + await context.Response.WriteAsync("Headers:" + Environment.NewLine); + foreach (var header in context.Request.Headers) + { + await context.Response.WriteAsync(header.Key + ": " + header.Value + Environment.NewLine); + } + await context.Response.WriteAsync(Environment.NewLine); + + await context.Response.WriteAsync("Environment Variables:" + Environment.NewLine); + var vars = Environment.GetEnvironmentVariables(); + foreach (var key in vars.Keys.Cast().OrderBy(key => key, StringComparer.OrdinalIgnoreCase)) + { + var value = vars[key]; + await context.Response.WriteAsync(key + ": " + value + Environment.NewLine); + } + await context.Response.WriteAsync(Environment.NewLine); + }); + } + + public static void Main(string[] args) + { + var host = new WebHostBuilder() + .ConfigureLogging(factory => + { + factory.AddConsole(); + }) + .UseKestrel() + .UseAzureAppServices() + .UseStartup() + .Build(); + + host.Run(); + } + } +} + diff --git a/src/AzureIntegration/src/Directory.Build.props b/src/AzureIntegration/src/Directory.Build.props new file mode 100644 index 0000000000..4f07cbc45d --- /dev/null +++ b/src/AzureIntegration/src/Directory.Build.props @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServices.HostingStartup/AssemblyInfo.cs b/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServices.HostingStartup/AssemblyInfo.cs new file mode 100644 index 0000000000..6852ee94a9 --- /dev/null +++ b/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServices.HostingStartup/AssemblyInfo.cs @@ -0,0 +1,6 @@ +// 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.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.AzureAppServicesIntegration.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServices.HostingStartup/AzureAppServicesHostingStartup.cs b/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServices.HostingStartup/AzureAppServicesHostingStartup.cs new file mode 100644 index 0000000000..5987e7cb58 --- /dev/null +++ b/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServices.HostingStartup/AzureAppServicesHostingStartup.cs @@ -0,0 +1,32 @@ +// 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.Hosting; + +[assembly: HostingStartup(typeof(Microsoft.AspNetCore.AzureAppServices.HostingStartup.AzureAppServicesHostingStartup))] + +namespace Microsoft.AspNetCore.AzureAppServices.HostingStartup +{ + /// + /// A dynamic azure lightup experiance + /// + public class AzureAppServicesHostingStartup : IHostingStartup + { + private const string HostingStartupName = "AppServices"; + private const string DiagnosticsFeatureName = "DiagnosticsEnabled"; + + /// + /// Calls UseAzureAppServices + /// + /// + public void Configure(IWebHostBuilder builder) + { + var baseConfiguration = HostingStartupConfigurationExtensions.GetBaseConfiguration(); + + if (baseConfiguration.IsEnabled(HostingStartupName, DiagnosticsFeatureName)) + { + builder.UseAzureAppServices(); + } + } + } +} diff --git a/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServices.HostingStartup/HostingStartupConfigurationExtensions.cs b/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServices.HostingStartup/HostingStartupConfigurationExtensions.cs new file mode 100644 index 0000000000..55ffdc6710 --- /dev/null +++ b/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServices.HostingStartup/HostingStartupConfigurationExtensions.cs @@ -0,0 +1,33 @@ +// 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.Extensions.Configuration; + +namespace Microsoft.AspNetCore.Hosting +{ + internal static class HostingStartupConfigurationExtensions + { + public static IConfiguration GetBaseConfiguration() + { + return new ConfigurationBuilder() + .AddEnvironmentVariables(prefix: "ASPNETCORE_") + .Build(); + } + public static bool IsEnabled(this IConfiguration configuration, string hostingStartupName, string featureName) + { + if (configuration.TryGetOption(hostingStartupName, featureName, out var value)) + { + value = value.ToLowerInvariant(); + return value != "false" && value != "0"; + } + + return true; + } + + public static bool TryGetOption(this IConfiguration configuration, string hostingStartupName, string featureName, out string value) + { + value = configuration[$"HostingStartup:{hostingStartupName}:{featureName}"]; + return !string.IsNullOrEmpty(value); + } + } +} \ No newline at end of file diff --git a/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServices.HostingStartup/Microsoft.AspNetCore.AzureAppServices.HostingStartup.csproj b/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServices.HostingStartup/Microsoft.AspNetCore.AzureAppServices.HostingStartup.csproj new file mode 100644 index 0000000000..37da02ef70 --- /dev/null +++ b/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServices.HostingStartup/Microsoft.AspNetCore.AzureAppServices.HostingStartup.csproj @@ -0,0 +1,20 @@ + + + + + + ASP.NET Core lightup integration with Azure AppServices. + netcoreapp3.0 + true + aspnetcore;azure;appservices + + + + + + + + + + + diff --git a/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServices.HostingStartup/baseline.netcore.json b/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServices.HostingStartup/baseline.netcore.json new file mode 100644 index 0000000000..e294148f6c --- /dev/null +++ b/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServices.HostingStartup/baseline.netcore.json @@ -0,0 +1,39 @@ +{ + "AssemblyIdentity": "Microsoft.AspNetCore.AzureAppServices.HostingStartup, Version=2.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "Types": [ + { + "Name": "Microsoft.AspNetCore.AzureAppServices.HostingStartup.AzureAppServicesHostingStartup", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Hosting.IHostingStartup" + ], + "Members": [ + { + "Kind": "Method", + "Name": "Configure", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Hosting.IWebHostBuilder" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Hosting.IHostingStartup", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + } + ] +} \ No newline at end of file diff --git a/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServices.HostingStartup/baseline.netframework.json b/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServices.HostingStartup/baseline.netframework.json new file mode 100644 index 0000000000..8aa1ebedab --- /dev/null +++ b/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServices.HostingStartup/baseline.netframework.json @@ -0,0 +1,39 @@ +{ + "AssemblyIdentity": "Microsoft.AspNetCore.AzureAppServices.HostingStartup, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "Types": [ + { + "Name": "Microsoft.AspNetCore.AzureAppServices.HostingStartup.AzureAppServicesHostingStartup", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Hosting.IHostingStartup" + ], + "Members": [ + { + "Kind": "Method", + "Name": "Configure", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Hosting.IWebHostBuilder" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Hosting.IHostingStartup", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + } + ] +} \ No newline at end of file diff --git a/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServicesIntegration/AppServicesWebHostBuilderExtensions.cs b/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServicesIntegration/AppServicesWebHostBuilderExtensions.cs new file mode 100644 index 0000000000..09a51bf56d --- /dev/null +++ b/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServicesIntegration/AppServicesWebHostBuilderExtensions.cs @@ -0,0 +1,28 @@ +// 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.Extensions.Logging; + +namespace Microsoft.AspNetCore.Hosting +{ + public static class AppServicesWebHostBuilderExtensions + { + /// + /// Configures application to use Azure AppServices integration. + /// + /// + /// + public static IWebHostBuilder UseAzureAppServices(this IWebHostBuilder hostBuilder) + { + if (hostBuilder == null) + { + throw new ArgumentNullException(nameof(hostBuilder)); + } +#pragma warning disable 618 + hostBuilder.ConfigureLogging(builder => builder.AddAzureWebAppDiagnostics()); +#pragma warning restore 618 + return hostBuilder; + } + } +} diff --git a/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServicesIntegration/Microsoft.AspNetCore.AzureAppServicesIntegration.csproj b/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServicesIntegration/Microsoft.AspNetCore.AzureAppServicesIntegration.csproj new file mode 100644 index 0000000000..dd72a33a90 --- /dev/null +++ b/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServicesIntegration/Microsoft.AspNetCore.AzureAppServicesIntegration.csproj @@ -0,0 +1,17 @@ + + + + ASP.NET Core integration with Azure AppServices. + netcoreapp3.0 + $(NoWarn);CS1591 + true + true + aspnetcore;azure;appservices + + + + + + + + diff --git a/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServicesIntegration/Properties/AssemblyInfo.cs b/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServicesIntegration/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..15e5bb66e2 --- /dev/null +++ b/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServicesIntegration/Properties/AssemblyInfo.cs @@ -0,0 +1,6 @@ +// 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.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Hosting.Azure.AppServices.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServicesIntegration/baseline.netcore.json b/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServicesIntegration/baseline.netcore.json new file mode 100644 index 0000000000..8a54cb63db --- /dev/null +++ b/src/AzureIntegration/src/Microsoft.AspNetCore.AzureAppServicesIntegration/baseline.netcore.json @@ -0,0 +1,32 @@ +{ + "AssemblyIdentity": "Microsoft.AspNetCore.AzureAppServicesIntegration, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "Types": [ + { + "Name": "Microsoft.AspNetCore.Hosting.AppServicesWebHostBuilderExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "UseAzureAppServices", + "Parameters": [ + { + "Name": "hostBuilder", + "Type": "Microsoft.AspNetCore.Hosting.IWebHostBuilder" + } + ], + "ReturnType": "Microsoft.AspNetCore.Hosting.IWebHostBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + } + ] +} \ No newline at end of file diff --git a/src/AzureIntegration/src/Microsoft.Extensions.ApplicationModelDetection/AppModelDetectionResult.cs b/src/AzureIntegration/src/Microsoft.Extensions.ApplicationModelDetection/AppModelDetectionResult.cs new file mode 100644 index 0000000000..96e53dc52d --- /dev/null +++ b/src/AzureIntegration/src/Microsoft.Extensions.ApplicationModelDetection/AppModelDetectionResult.cs @@ -0,0 +1,12 @@ +// 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. + +namespace Microsoft.Extensions.ApplicationModelDetection +{ + public class AppModelDetectionResult + { + public RuntimeFramework? Framework { get; set; } + public string FrameworkVersion { get; set; } + public string AspNetCoreVersion { get; set; } + } +} \ No newline at end of file diff --git a/src/AzureIntegration/src/Microsoft.Extensions.ApplicationModelDetection/AppModelDetector.cs b/src/AzureIntegration/src/Microsoft.Extensions.ApplicationModelDetection/AppModelDetector.cs new file mode 100644 index 0000000000..e42a8f2918 --- /dev/null +++ b/src/AzureIntegration/src/Microsoft.Extensions.ApplicationModelDetection/AppModelDetector.cs @@ -0,0 +1,250 @@ +// 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.Linq; +using System.Reflection.Metadata; +using System.Reflection.PortableExecutable; +using System.Xml.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Microsoft.Extensions.ApplicationModelDetection +{ + public class AppModelDetector + { + // We use Hosting package to detect AspNetCore version + // it contains light-up implemenation that we care about and + // would have to be used by aspnet core web apps + private const string AspNetCoreAssembly = "Microsoft.AspNetCore.Hosting"; + + /// + /// Reads the following sources + /// - web.config to detect dotnet framework kind + /// - *.runtimeconfig.json to detect target framework version + /// - *.deps.json to detect Asp.Net Core version + /// - Microsoft.AspNetCore.Hosting.dll to detect Asp.Net Core version + /// + /// The application directory + /// The instance containing information about application + public AppModelDetectionResult Detect(DirectoryInfo directory) + { + string entryPoint = null; + + // Try reading web.config and resolving framework and app path + var webConfig = directory.GetFiles("web.config").FirstOrDefault(); + + bool webConfigExists = webConfig != null; + bool? usesDotnetExe = null; + + if (webConfigExists && + TryParseWebConfig(webConfig, out var dotnetExe, out entryPoint)) + { + usesDotnetExe = dotnetExe; + } + + // If we found entry point let's look for .deps.json + // in some cases it exists in desktop too + FileInfo depsJson = null; + FileInfo runtimeConfig = null; + + if (!string.IsNullOrWhiteSpace(entryPoint)) + { + depsJson = new FileInfo(Path.ChangeExtension(entryPoint, ".deps.json")); + runtimeConfig = new FileInfo(Path.ChangeExtension(entryPoint, ".runtimeconfig.json")); + } + + if (depsJson == null || !depsJson.Exists) + { + depsJson = directory.GetFiles("*.deps.json").FirstOrDefault(); + } + + if (runtimeConfig == null || !runtimeConfig.Exists) + { + runtimeConfig = directory.GetFiles("*.runtimeconfig.json").FirstOrDefault(); + } + + string aspNetCoreVersionFromDeps = null; + string aspNetCoreVersionFromDll = null; + + + // Try to detect ASP.NET Core version from .deps.json + if (depsJson != null && + depsJson.Exists && + TryParseDependencies(depsJson, out var aspNetCoreVersion)) + { + aspNetCoreVersionFromDeps = aspNetCoreVersion; + } + + // Try to detect ASP.NET Core version from .deps.json + var aspNetCoreDll = directory.GetFiles(AspNetCoreAssembly + ".dll").FirstOrDefault(); + if (aspNetCoreDll != null && + TryParseAssembly(aspNetCoreDll, out aspNetCoreVersion)) + { + aspNetCoreVersionFromDll = aspNetCoreVersion; + } + + // Try to detect dotnet core runtime version from runtimeconfig.json + string runtimeVersionFromRuntimeConfig = null; + if (runtimeConfig != null && + runtimeConfig.Exists) + { + TryParseRuntimeConfig(runtimeConfig, out runtimeVersionFromRuntimeConfig); + } + + var result = new AppModelDetectionResult(); + if (usesDotnetExe == true) + { + result.Framework = RuntimeFramework.DotNetCore; + result.FrameworkVersion = runtimeVersionFromRuntimeConfig; + } + else + { + if (depsJson?.Exists == true && + runtimeConfig?.Exists == true) + { + result.Framework = RuntimeFramework.DotNetCoreStandalone; + } + else + { + result.Framework = RuntimeFramework.DotNetFramework; + } + } + + result.AspNetCoreVersion = aspNetCoreVersionFromDeps ?? aspNetCoreVersionFromDll; + + return result; + } + + private bool TryParseAssembly(FileInfo aspNetCoreDll, out string aspNetCoreVersion) + { + aspNetCoreVersion = null; + try + { + using (var stream = aspNetCoreDll.OpenRead()) + using (var peReader = new PEReader(stream)) + { + var metadataReader = peReader.GetMetadataReader(); + var assemblyDefinition = metadataReader.GetAssemblyDefinition(); + aspNetCoreVersion = assemblyDefinition.Version.ToString(); + return true; + } + } + catch (Exception) + { + return false; + } + } + + /// + /// Search for Microsoft.AspNetCore.Hosting entry in deps.json and get it's version number + /// + private bool TryParseDependencies(FileInfo depsJson, out string aspnetCoreVersion) + { + aspnetCoreVersion = null; + try + { + using (var streamReader = depsJson.OpenText()) + using (var jsonReader = new JsonTextReader(streamReader)) + { + var json = JObject.Load(jsonReader); + + var libraryPrefix = AspNetCoreAssembly+ "/"; + + var library = json.Descendants().OfType().FirstOrDefault(property => property.Name.StartsWith(libraryPrefix)); + if (library != null) + { + aspnetCoreVersion = library.Name.Substring(libraryPrefix.Length); + return true; + } + } + } + catch (Exception) + { + } + return false; + } + + private bool TryParseRuntimeConfig(FileInfo runtimeConfig, out string frameworkVersion) + { + frameworkVersion = null; + try + { + using (var streamReader = runtimeConfig.OpenText()) + using (var jsonReader = new JsonTextReader(streamReader)) + { + var json = JObject.Load(jsonReader); + frameworkVersion = (string)json?["runtimeOptions"] + ?["framework"] + ?["version"]; + + return true; + } + } + catch (Exception) + { + return false; + } + } + + private bool TryParseWebConfig(FileInfo webConfig, out bool usesDotnetExe, out string entryPoint) + { + usesDotnetExe = false; + entryPoint = null; + + try + { + var xdocument = XDocument.Load(webConfig.FullName); + var aspNetCoreHandler = xdocument.Root? + .Element("system.webServer") + .Element("aspNetCore"); + + if (aspNetCoreHandler == null) + { + return false; + } + + var processPath = (string) aspNetCoreHandler.Attribute("processPath"); + var arguments = (string) aspNetCoreHandler.Attribute("arguments"); + + if (processPath.EndsWith("dotnet", StringComparison.OrdinalIgnoreCase) || + processPath.EndsWith("dotnet.exe", StringComparison.OrdinalIgnoreCase) && + !string.IsNullOrWhiteSpace(arguments)) + { + usesDotnetExe = true; + var entryPointPart = arguments.Split(new[] {" "}, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault(); + + if (!string.IsNullOrWhiteSpace(entryPointPart)) + { + try + { + entryPoint = Path.GetFullPath(Path.Combine(webConfig.DirectoryName, entryPointPart)); + } + catch (Exception) + { + } + } + } + else + { + usesDotnetExe = false; + + try + { + entryPoint = Path.GetFullPath(Path.Combine(webConfig.DirectoryName, processPath)); + } + catch (Exception) + { + } + } + } + catch (Exception) + { + return false; + } + + return true; + } + } +} \ No newline at end of file diff --git a/src/AzureIntegration/src/Microsoft.Extensions.ApplicationModelDetection/Microsoft.Extensions.ApplicationModelDetection.csproj b/src/AzureIntegration/src/Microsoft.Extensions.ApplicationModelDetection/Microsoft.Extensions.ApplicationModelDetection.csproj new file mode 100644 index 0000000000..ccb195cee2 --- /dev/null +++ b/src/AzureIntegration/src/Microsoft.Extensions.ApplicationModelDetection/Microsoft.Extensions.ApplicationModelDetection.csproj @@ -0,0 +1,15 @@ + + + ASP.NET Core integration with Azure AppServices. + netcoreapp3.0 + $(NoWarn);CS1591 + true + true + aspnetcore;azure;appservices + + + + + + + diff --git a/src/AzureIntegration/src/Microsoft.Extensions.ApplicationModelDetection/RuntimeFramework.cs b/src/AzureIntegration/src/Microsoft.Extensions.ApplicationModelDetection/RuntimeFramework.cs new file mode 100644 index 0000000000..b182c79eec --- /dev/null +++ b/src/AzureIntegration/src/Microsoft.Extensions.ApplicationModelDetection/RuntimeFramework.cs @@ -0,0 +1,12 @@ +// 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. + +namespace Microsoft.Extensions.ApplicationModelDetection +{ + public enum RuntimeFramework + { + DotNetCore, + DotNetCoreStandalone, + DotNetFramework + } +} \ No newline at end of file diff --git a/src/AzureIntegration/src/Microsoft.Extensions.ApplicationModelDetection/baseline.netcore.json b/src/AzureIntegration/src/Microsoft.Extensions.ApplicationModelDetection/baseline.netcore.json new file mode 100644 index 0000000000..d94df11f0a --- /dev/null +++ b/src/AzureIntegration/src/Microsoft.Extensions.ApplicationModelDetection/baseline.netcore.json @@ -0,0 +1,144 @@ +{ + "AssemblyIdentity": "Microsoft.Extensions.ApplicationModelDetection, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "Types": [ + { + "Name": "Microsoft.Extensions.ApplicationModelDetection.AppModelDetectionResult", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_Framework", + "Parameters": [], + "ReturnType": "System.Nullable", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Framework", + "Parameters": [ + { + "Name": "value", + "Type": "System.Nullable" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_FrameworkVersion", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_FrameworkVersion", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_AspNetCoreVersion", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_AspNetCoreVersion", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.Extensions.ApplicationModelDetection.AppModelDetector", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Detect", + "Parameters": [ + { + "Name": "directory", + "Type": "System.IO.DirectoryInfo" + } + ], + "ReturnType": "Microsoft.Extensions.ApplicationModelDetection.AppModelDetectionResult", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.Extensions.ApplicationModelDetection.RuntimeFramework", + "Visibility": "Public", + "Kind": "Enumeration", + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Field", + "Name": "DotNetCore", + "Parameters": [], + "GenericParameter": [], + "Literal": "0" + }, + { + "Kind": "Field", + "Name": "DotNetCoreStandalone", + "Parameters": [], + "GenericParameter": [], + "Literal": "1" + }, + { + "Kind": "Field", + "Name": "DotNetFramework", + "Parameters": [], + "GenericParameter": [], + "Literal": "2" + } + ], + "GenericParameters": [] + } + ] +} \ No newline at end of file diff --git a/src/AzureIntegration/src/Microsoft.Web.Xdt.Extensions/InsertOrAppendAttribute.cs b/src/AzureIntegration/src/Microsoft.Web.Xdt.Extensions/InsertOrAppendAttribute.cs new file mode 100644 index 0000000000..c2e711cb93 --- /dev/null +++ b/src/AzureIntegration/src/Microsoft.Web.Xdt.Extensions/InsertOrAppendAttribute.cs @@ -0,0 +1,144 @@ +// 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.Xml; +using Microsoft.Web.XmlTransform; + +namespace Microsoft.Web.Xdt.Extensions +{ + /// + /// Insert or append to the given attribute + /// + public class InsertOrAppendAttribute : Transform + { + /// + /// + /// + public InsertOrAppendAttribute() + : base(TransformFlags.UseParentAsTargetNode, MissingTargetMessage.Error) + { + } + + private string _attributeName; + + /// + /// + /// + protected string AttributeName + { + get + { + if (_attributeName == null) + { + _attributeName = GetArgumentValue("Attribute"); + } + return _attributeName; + } + } + + /// + /// Extracts a value from the arguments provided + /// + /// + /// + protected string GetArgumentValue(string name) + { + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentNullException(nameof(name)); + } + + string result = null; + if (Arguments != null && Arguments.Count > 0) + { + foreach (var arg in Arguments) + { + if (!string.IsNullOrEmpty(arg)) + { + var trimmedArg = arg.Trim(); + if (trimmedArg.StartsWith(name, StringComparison.OrdinalIgnoreCase)) + { + var start = arg.IndexOf('\''); + var last = arg.LastIndexOf('\''); + if (start <= 0 || last <= 0 || last <= start) + { + throw new ArgumentException("Expected two ['] characters"); + } + + var value = trimmedArg.Substring(start, last - start); + + // remove any leading or trailing ' + value = value.Trim().TrimStart('\'').TrimStart('\''); + result = value; + } + } + } + } + return result; + } + + /// + /// + /// + protected override void Apply() + { + if (TargetChildNodes == null || TargetChildNodes.Count == 0) + { + TargetNode.AppendChild(TransformNode); + } + else + { + XmlAttribute transformAtt = null; + + foreach (XmlAttribute att in TransformNode.Attributes) + { + if (string.Equals(att.Name, AttributeName, StringComparison.OrdinalIgnoreCase)) + { + transformAtt = att; + break; + } + } + + if (transformAtt == null) + { + throw new InvalidOperationException("No target attribute to append"); + } + + foreach (XmlNode targetNode in TargetChildNodes) + { + var foundAttribute = false; + foreach (XmlAttribute att in targetNode.Attributes) + { + if (string.Equals(att.Name, AttributeName, StringComparison.OrdinalIgnoreCase)) + { + foundAttribute = true; + if (string.IsNullOrEmpty(att.Value)) + { + att.Value = transformAtt.Value; + } + else + { + // TODO: This doesn't compose well with insertOrAppend being applied on the TargetNode. + // The target node is created with the children it has in the transform, which means we would + // duplicate the value here. + if (att.Value == transformAtt.Value) + { + return; + } + att.Value = $"{att.Value};{transformAtt.Value}"; + } + } + } + + if (!foundAttribute) + { + var attribute = targetNode.OwnerDocument.CreateAttribute(AttributeName); + attribute.Value = transformAtt.Value; + targetNode.Attributes.Append(attribute); + } + } + } + } + } +} \ No newline at end of file diff --git a/src/AzureIntegration/src/Microsoft.Web.Xdt.Extensions/Microsoft.Web.Xdt.Extensions.csproj b/src/AzureIntegration/src/Microsoft.Web.Xdt.Extensions/Microsoft.Web.Xdt.Extensions.csproj new file mode 100644 index 0000000000..4222ec4e2d --- /dev/null +++ b/src/AzureIntegration/src/Microsoft.Web.Xdt.Extensions/Microsoft.Web.Xdt.Extensions.csproj @@ -0,0 +1,14 @@ + + + + Additional functionality for Xdt transforms. + net461 + true + xdt + + + + + + + \ No newline at end of file diff --git a/src/AzureIntegration/src/Microsoft.Web.Xdt.Extensions/baseline.netframework.json b/src/AzureIntegration/src/Microsoft.Web.Xdt.Extensions/baseline.netframework.json new file mode 100644 index 0000000000..202b401f50 --- /dev/null +++ b/src/AzureIntegration/src/Microsoft.Web.Xdt.Extensions/baseline.netframework.json @@ -0,0 +1,53 @@ +{ + "AssemblyIdentity": "Microsoft.Web.Xdt.Extensions, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "Types": [ + { + "Name": "Microsoft.Web.Xdt.Extensions.InsertOrAppendAttribute", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.Web.XmlTransform.Transform", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_AttributeName", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "GetArgumentValue", + "Parameters": [ + { + "Name": "name", + "Type": "System.String" + } + ], + "ReturnType": "System.String", + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Apply", + "Parameters": [], + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + } + ] +} \ No newline at end of file diff --git a/src/AzureIntegration/test/Directory.Build.props b/src/AzureIntegration/test/Directory.Build.props new file mode 100644 index 0000000000..f1ae8d1fe4 --- /dev/null +++ b/src/AzureIntegration/test/Directory.Build.props @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/AzureIntegration/test/Microsoft.AspNetCore.AzureAppServicesIntegration.Tests/AppServicesWebHostBuilderExtensionsTest.cs b/src/AzureIntegration/test/Microsoft.AspNetCore.AzureAppServicesIntegration.Tests/AppServicesWebHostBuilderExtensionsTest.cs new file mode 100644 index 0000000000..d3aa47bba5 --- /dev/null +++ b/src/AzureIntegration/test/Microsoft.AspNetCore.AzureAppServicesIntegration.Tests/AppServicesWebHostBuilderExtensionsTest.cs @@ -0,0 +1,24 @@ +// 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.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Moq; +using Xunit; + +namespace Microsoft.AspNetCore.Hosting.Azure.AppServices.Tests +{ + public class AppServicesWebHostBuilderExtensionsTest + { + [Fact] + public void UseAzureAppServices_RegisterLogger() + { + var mock = new Mock(); + + mock.Object.UseAzureAppServices(); + + mock.Verify(builder => builder.ConfigureServices(It.IsNotNull>()), Times.Once); + } + } +} diff --git a/src/AzureIntegration/test/Microsoft.AspNetCore.AzureAppServicesIntegration.Tests/Microsoft.AspNetCore.AzureAppServicesIntegration.Tests.csproj b/src/AzureIntegration/test/Microsoft.AspNetCore.AzureAppServicesIntegration.Tests/Microsoft.AspNetCore.AzureAppServicesIntegration.Tests.csproj new file mode 100644 index 0000000000..039fe663b8 --- /dev/null +++ b/src/AzureIntegration/test/Microsoft.AspNetCore.AzureAppServicesIntegration.Tests/Microsoft.AspNetCore.AzureAppServicesIntegration.Tests.csproj @@ -0,0 +1,16 @@ + + + + netcoreapp3.0 + + + + + + + + + + + + diff --git a/src/AzureIntegration/test/Microsoft.Extensions.ApplicationModelDetection.Tests/AppModelTests.cs b/src/AzureIntegration/test/Microsoft.Extensions.ApplicationModelDetection.Tests/AppModelTests.cs new file mode 100644 index 0000000000..02e420d2e4 --- /dev/null +++ b/src/AzureIntegration/test/Microsoft.Extensions.ApplicationModelDetection.Tests/AppModelTests.cs @@ -0,0 +1,229 @@ +// // 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.Hosting; +using Xunit; + +namespace Microsoft.Extensions.ApplicationModelDetection.Tests +{ + public class AppModelTests + { + private const string EmptyWebConfig = @""; + + [Theory] + [InlineData("dotnet")] + [InlineData("dotnet.exe")] + [InlineData("%HOME%/dotnet")] + [InlineData("%HOME%/dotnet.exe")] + [InlineData("DoTNeT.ExE")] + public void DetectsCoreFrameworkFromWebConfig(string processPath) + { + using (var temp = new TemporaryDirectory() + .WithFile("web.config",GenerateWebConfig(processPath, ".\\app.dll"))) + { + var result = new AppModelDetector().Detect(temp.Directory); + Assert.Equal(RuntimeFramework.DotNetCore, result.Framework); + } + } + + [Theory] + [InlineData("app")] + [InlineData("app.exe")] + [InlineData("%HOME%/app")] + [InlineData("%HOME%/app.exe")] + public void DetectsFullFrameworkFromWebConfig(string processPath) + { + using (var temp = new TemporaryDirectory() + .WithFile("web.config", GenerateWebConfig(processPath, ".\\app.dll"))) + { + var result = new AppModelDetector().Detect(temp.Directory); + Assert.Equal(RuntimeFramework.DotNetFramework, result.Framework); + } + } + + [Theory] + [InlineData("2.0.0")] + [InlineData("2.0.0-preview1")] + [InlineData("1.1.3")] + public void DetectsRuntimeVersionFromRuntimeConfig(string runtimeVersion) + { + using (var temp = new TemporaryDirectory() + .WithFile("web.config", GenerateWebConfig("dotnet", ".\\app.dll")) + .WithFile("app.runtimeconfig.json", @"{ + ""runtimeOptions"": { + ""tfm"": ""netcoreapp2.0"", + ""framework"": { + ""name"": ""Microsoft.NETCore.App"", + ""version"": """+ runtimeVersion + @""" + }, + ""configProperties"": { + ""System.GC.Server"": true + } + } +}")) + { + var result = new AppModelDetector().Detect(temp.Directory); + Assert.Equal(RuntimeFramework.DotNetCore, result.Framework); + Assert.Equal(runtimeVersion, result.FrameworkVersion); + } + } + + + [Theory] + [InlineData("2.0.0")] + [InlineData("2.0.0-preview1")] + [InlineData("1.1.3")] + public void DetectsRuntimeVersionFromRuntimeConfigWitoutEntryPoint(string runtimeVersion) + { + using (var temp = new TemporaryDirectory() + .WithFile("web.config", GenerateWebConfig("dotnet", "%HOME%\\app.dll")) + .WithFile("app.runtimeconfig.json", @"{ + ""runtimeOptions"": { + ""tfm"": ""netcoreapp2.0"", + ""framework"": { + ""name"": ""Microsoft.NETCore.App"", + ""version"": """+ runtimeVersion + @""" + }, + ""configProperties"": { + ""System.GC.Server"": true + } + } +}")) + { + var result = new AppModelDetector().Detect(temp.Directory); + Assert.Equal(RuntimeFramework.DotNetCore, result.Framework); + Assert.Equal(runtimeVersion, result.FrameworkVersion); + } + } + + [Theory] + [InlineData("2.0.0")] + [InlineData("2.0.0-preview1")] + [InlineData("1.1.3")] + public void DetectsAspNetCoreVersionFromDepsFile(string runtimeVersion) + { + using (var temp = new TemporaryDirectory() + .WithFile("web.config", GenerateWebConfig("dotnet", "app.dll")) + .WithFile("app.deps.json", @"{ + ""targets"": { + "".NETCoreApp,Version=v2.7"": { + ""Microsoft.AspNetCore.Hosting/" + runtimeVersion + @""": { } + } + } +}")) + { + var result = new AppModelDetector().Detect(temp.Directory); + Assert.Equal(RuntimeFramework.DotNetCore, result.Framework); + Assert.Equal(runtimeVersion, result.AspNetCoreVersion); + } + } + + [Theory] + [InlineData("2.0.0")] + [InlineData("2.0.0-preview1")] + [InlineData("1.1.3")] + public void DetectsAspNetCoreVersionFromDepsFileWithoutEntryPoint(string runtimeVersion) + { + using (var temp = new TemporaryDirectory() + .WithFile("web.config", GenerateWebConfig("dotnet", "%HOME%\\app.dll")) + .WithFile("app.deps.json", @"{ + ""targets"": { + "".NETCoreApp,Version=v2.7"": { + ""Microsoft.AspNetCore.Hosting/" + runtimeVersion + @""": { } + } + } +}")) + { + var result = new AppModelDetector().Detect(temp.Directory); + Assert.Equal(RuntimeFramework.DotNetCore, result.Framework); + Assert.Equal(runtimeVersion, result.AspNetCoreVersion); + } + } + + [Fact] + public void DetectsFullFrameworkWhenWebConfigExists() + { + using (var temp = new TemporaryDirectory() + .WithFile("web.config", EmptyWebConfig)) + { + var result = new AppModelDetector().Detect(temp.Directory); + Assert.Equal(RuntimeFramework.DotNetFramework, result.Framework); + } + } + + [Fact] + public void DetectsStandalone_WhenBothDepsAndRuntimeConfigExist() + { + using (var temp = new TemporaryDirectory() + .WithFile("web.config", GenerateWebConfig("app.exe", "")) + .WithFile("app.runtimeconfig.json", "{}") + .WithFile("app.deps.json", "{}")) + { + var result = new AppModelDetector().Detect(temp.Directory); + Assert.Equal(RuntimeFramework.DotNetCoreStandalone, result.Framework); + } + } + + [Fact] + public void DetectsAspNetCoreVersionFromHostingDll() + { + using (var temp = new TemporaryDirectory() + .WithFile(typeof(WebHostBuilder).Assembly.Location)) + { + var result = new AppModelDetector().Detect(temp.Directory); + Assert.Equal(typeof(WebHostBuilder).Assembly.GetName().Version.ToString(), result.AspNetCoreVersion); + } + } + + private static string GenerateWebConfig(string processPath, string arguments) + { + return $@" + + + + + + + + +"; + } + + private class TemporaryDirectory: IDisposable + { + public TemporaryDirectory() + { + Directory = new DirectoryInfo(Path.GetTempPath()) + .CreateSubdirectory(Guid.NewGuid().ToString("N")); + } + + public DirectoryInfo Directory { get; } + + public void Dispose() + { + try + { + Directory.Delete(true); + } + catch (IOException) + { + } + } + + public TemporaryDirectory WithFile(string name, string value) + { + File.WriteAllText(Path.Combine(Directory.FullName, name), value); + return this; + } + + + public TemporaryDirectory WithFile(string name) + { + File.Copy(name, Path.Combine(Directory.FullName, Path.GetFileName(name))); + return this; + } + } + } +} \ No newline at end of file diff --git a/src/AzureIntegration/test/Microsoft.Extensions.ApplicationModelDetection.Tests/Microsoft.Extensions.ApplicationModelDetection.Tests.csproj b/src/AzureIntegration/test/Microsoft.Extensions.ApplicationModelDetection.Tests/Microsoft.Extensions.ApplicationModelDetection.Tests.csproj new file mode 100644 index 0000000000..b95c066f61 --- /dev/null +++ b/src/AzureIntegration/test/Microsoft.Extensions.ApplicationModelDetection.Tests/Microsoft.Extensions.ApplicationModelDetection.Tests.csproj @@ -0,0 +1,11 @@ + + + + netcoreapp3.0 + + + + + + + diff --git a/src/AzureIntegration/test/Microsoft.Web.Xdt.Extensions.Tests/InsertOrAppendAttributeTests.cs b/src/AzureIntegration/test/Microsoft.Web.Xdt.Extensions.Tests/InsertOrAppendAttributeTests.cs new file mode 100644 index 0000000000..546631f14f --- /dev/null +++ b/src/AzureIntegration/test/Microsoft.Web.Xdt.Extensions.Tests/InsertOrAppendAttributeTests.cs @@ -0,0 +1,109 @@ +// 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.IO; +using System.Xml; +using Microsoft.Web.XmlTransform; +using Xunit; + +namespace Microsoft.Web.Xdt.Extensions +{ + public class InsertOrAppendAttributeTests + { + [Fact] + public void InsertOrAppend_NoExesitingLine_InsertsLine() + { + var transform = new XmlTransformation(Path.GetFullPath("transform.xdt")); + var doc = new XmlDocument(); + doc.Load("config_empty.xml"); + Assert.True(transform.Apply(doc)); + + Assert.Equal(2, doc.ChildNodes.Count); + var configurationNode = doc["configuration"]; + + Assert.Equal(2, configurationNode.ChildNodes.Count); + + var firstChild = configurationNode.FirstChild; + Assert.Equal("add", firstChild.Name); + Assert.Equal("KeyName1", firstChild.Attributes["name"].Value); + Assert.Equal("InsertValue1", firstChild.Attributes["value"].Value); + + var secondChild = firstChild.NextSibling; + Assert.Equal("add", secondChild.Name); + Assert.Equal("KeyName2", secondChild.Attributes["name"].Value); + Assert.Equal("InsertValue2", secondChild.Attributes["value"].Value); + } + + [Fact] + public void InsertOrAppend_LineExistsButNoValueField_FieldInserted() + { + var transform = new XmlTransformation(Path.GetFullPath("transform.xdt")); + var doc = new XmlDocument(); + doc.Load("config_existingline.xml"); + Assert.True(transform.Apply(doc)); + + Assert.Equal(2, doc.ChildNodes.Count); + var configurationNode = doc["configuration"]; + + Assert.Equal(2, configurationNode.ChildNodes.Count); + + var firstChild = configurationNode.FirstChild; + Assert.Equal("add", firstChild.Name); + Assert.Equal("KeyName1", firstChild.Attributes["name"].Value); + Assert.Equal("InsertValue1", firstChild.Attributes["value"].Value); + + var secondChild = firstChild.NextSibling; + Assert.Equal("add", secondChild.Name); + Assert.Equal("KeyName2", secondChild.Attributes["name"].Value); + Assert.Equal("InsertValue2", secondChild.Attributes["value"].Value); + } + + [Fact] + public void InsertOrAppend_ExistingEmptyValue_InsertsValue() + { + var transform = new XmlTransformation(Path.GetFullPath("transform.xdt")); + var doc = new XmlDocument(); + doc.Load("config_existingemptyvalue.xml"); + Assert.True(transform.Apply(doc)); + + Assert.Equal(2, doc.ChildNodes.Count); + var configurationNode = doc["configuration"]; + + Assert.Equal(2, configurationNode.ChildNodes.Count); + + var firstChild = configurationNode.FirstChild; + Assert.Equal("add", firstChild.Name); + Assert.Equal("KeyName1", firstChild.Attributes["name"].Value); + Assert.Equal("InsertValue1", firstChild.Attributes["value"].Value); + + var secondChild = firstChild.NextSibling; + Assert.Equal("add", secondChild.Name); + Assert.Equal("KeyName2", secondChild.Attributes["name"].Value); + Assert.Equal("InsertValue2", secondChild.Attributes["value"].Value); + } + + [Fact] + public void InsertOrAppend_ExistingValue_AppendsValue() + { + var transform = new XmlTransformation(Path.GetFullPath("transform.xdt")); + var doc = new XmlDocument(); + doc.Load("config_existingvalue.xml"); + Assert.True(transform.Apply(doc)); + + Assert.Equal(2, doc.ChildNodes.Count); + var configurationNode = doc["configuration"]; + + Assert.Equal(2, configurationNode.ChildNodes.Count); + + var firstChild = configurationNode.FirstChild; + Assert.Equal("add", firstChild.Name); + Assert.Equal("KeyName1", firstChild.Attributes["name"].Value); + Assert.Equal("ExistingValue1;InsertValue1", firstChild.Attributes["value"].Value); + + var secondChild = firstChild.NextSibling; + Assert.Equal("add", secondChild.Name); + Assert.Equal("KeyName2", secondChild.Attributes["name"].Value); + Assert.Equal("ExistingValue2;InsertValue2", secondChild.Attributes["value"].Value); + } + } +} diff --git a/src/AzureIntegration/test/Microsoft.Web.Xdt.Extensions.Tests/Microsoft.Web.Xdt.Extensions.Tests.csproj b/src/AzureIntegration/test/Microsoft.Web.Xdt.Extensions.Tests/Microsoft.Web.Xdt.Extensions.Tests.csproj new file mode 100644 index 0000000000..026516e0ae --- /dev/null +++ b/src/AzureIntegration/test/Microsoft.Web.Xdt.Extensions.Tests/Microsoft.Web.Xdt.Extensions.Tests.csproj @@ -0,0 +1,33 @@ + + + + net461 + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + + + + diff --git a/src/AzureIntegration/test/Microsoft.Web.Xdt.Extensions.Tests/config_empty.xml b/src/AzureIntegration/test/Microsoft.Web.Xdt.Extensions.Tests/config_empty.xml new file mode 100644 index 0000000000..1156926c52 --- /dev/null +++ b/src/AzureIntegration/test/Microsoft.Web.Xdt.Extensions.Tests/config_empty.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/AzureIntegration/test/Microsoft.Web.Xdt.Extensions.Tests/config_existingemptyvalue.xml b/src/AzureIntegration/test/Microsoft.Web.Xdt.Extensions.Tests/config_existingemptyvalue.xml new file mode 100644 index 0000000000..66299d8c9e --- /dev/null +++ b/src/AzureIntegration/test/Microsoft.Web.Xdt.Extensions.Tests/config_existingemptyvalue.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/AzureIntegration/test/Microsoft.Web.Xdt.Extensions.Tests/config_existingline.xml b/src/AzureIntegration/test/Microsoft.Web.Xdt.Extensions.Tests/config_existingline.xml new file mode 100644 index 0000000000..6a474e9808 --- /dev/null +++ b/src/AzureIntegration/test/Microsoft.Web.Xdt.Extensions.Tests/config_existingline.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/AzureIntegration/test/Microsoft.Web.Xdt.Extensions.Tests/config_existingvalue.xml b/src/AzureIntegration/test/Microsoft.Web.Xdt.Extensions.Tests/config_existingvalue.xml new file mode 100644 index 0000000000..f8a5cf3533 --- /dev/null +++ b/src/AzureIntegration/test/Microsoft.Web.Xdt.Extensions.Tests/config_existingvalue.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/AzureIntegration/test/Microsoft.Web.Xdt.Extensions.Tests/transform.xdt b/src/AzureIntegration/test/Microsoft.Web.Xdt.Extensions.Tests/transform.xdt new file mode 100644 index 0000000000..f62924ab31 --- /dev/null +++ b/src/AzureIntegration/test/Microsoft.Web.Xdt.Extensions.Tests/transform.xdt @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/src/AzureIntegration/version.props b/src/AzureIntegration/version.props new file mode 100644 index 0000000000..bcf920cf80 --- /dev/null +++ b/src/AzureIntegration/version.props @@ -0,0 +1,12 @@ + + + 3.0.0 + alpha1 + $(VersionPrefix) + $(VersionPrefix)-$(VersionSuffix)-final + t000 + a- + $(FeatureBranchVersionPrefix)$(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-')) + $(VersionSuffix)-$(BuildNumber) + +