diff options
author | James Newton-King <james@newtonking.com> | 2022-04-01 02:46:25 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-04-01 02:46:25 +0300 |
commit | dddffea59c3c8e16ce2ec43e43ae5ba5fc121943 (patch) | |
tree | 4160ad81ba9d3b391e3bffa3f55caf5b9c1be9a0 | |
parent | aca14e20a53b65d3defe3d827a1b1fa538a0c066 (diff) | |
parent | 7399df28dabaa316a37b043cf944f4433faf08ad (diff) |
Merge branch 'main' into jamesnk/trimming-docsjamesnk/trimming-docs
271 files changed, 2725 insertions, 873 deletions
diff --git a/.azure/pipelines/ci.yml b/.azure/pipelines/ci.yml index d59d36a5cf..ce8da1c3ad 100644 --- a/.azure/pipelines/ci.yml +++ b/.azure/pipelines/ci.yml @@ -24,6 +24,11 @@ parameters: default: false displayName: Skip tests? type: boolean +# Choose whether to enable binlogs when running pipeline manually. +- name: produceBinlogs + default: false + displayName: Produce binlogs? + type: boolean # Choose whether to test source indexing. Ignored in public builds. # Will cause inaccessible links on https://source.dot.net/ unless commits are also available in GitHub. - name: testSourceIndexing @@ -86,7 +91,7 @@ variables: - name: sourceIndexPackageSource value: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json - group: source-dot-net stage1 variables -- ${{ if or(eq(variables['System.TeamProject'], 'public'), in(variables['Build.Reason'], 'PullRequest')) }}: +- ${{ if or(eq(variables['System.TeamProject'], 'public'), in(variables['Build.Reason'], 'PullRequest'), eq(parameters.produceBinlogs, 'true')) }}: - name: _BuildArgs value: '/p:SkipTestBuild=true /p:PostBuildSign=$(PostBuildSign)' - name: _PublishArgs @@ -282,7 +287,13 @@ stages: includeForks: true - name: Windows_Packages path: artifacts/packages/ - + - name: Windows_HostingBundle + path: artifacts/bin/WindowsHostingBundle + - name: Windows_ANCM_Msi + path: artifacts/bin/ANCMv2 + - name: Windows_ANCMIISExpress_Msi + path: artifacts/bin/AncmIISExpressV2 + # Build Windows ARM - template: jobs/default-build.yml parameters: diff --git a/.editorconfig b/.editorconfig index e1181f237f..06b74cd958 100644 --- a/.editorconfig +++ b/.editorconfig @@ -263,7 +263,7 @@ dotnet_diagnostic.IDE0161.severity = warning dotnet_style_allow_multiple_blank_lines_experimental = false dotnet_diagnostic.IDE2000.severity = warning -[{eng/tools/**.cs,**/{test,testassets,samples,Samples,perf}/**.cs}] +[{eng/tools/**.cs,**/{test,testassets,samples,Samples,perf,scripts}/**.cs}] # CA1018: Mark attributes with AttributeUsageAttribute dotnet_diagnostic.CA1018.severity = suggestion # CA1507: Use nameof to express symbol names @@ -302,6 +302,8 @@ dotnet_diagnostic.CA1845.severity = suggestion dotnet_diagnostic.CA1846.severity = suggestion # CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters dotnet_diagnostic.CA1847.severity = suggestion +# CA2007: Consider calling ConfigureAwait on the awaited task +dotnet_diagnostic.CA2007.severity = suggestion # CA2008: Do not create tasks without passing a TaskScheduler dotnet_diagnostic.CA2008.severity = suggestion # CA2012: Use ValueTask correctly diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2b811a2676..fb9da1cada 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -22,6 +22,8 @@ /src/Components/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review @dotnet/aspnet-blazor-eng /src/DefaultBuilder/ @tratcher @halter73 /src/DefaultBuilder/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review @tratcher +/src/Grpc/ @JamesNK @captainsafia +/src/Grpc/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review @JamesNK @captainsafia /src/Hosting/ @tratcher @halter73 /src/Hosting/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review @tratcher /src/Http/ @tratcher @BrennanConroy @halter73 @@ -39,8 +41,8 @@ /src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/ @dotnet/aspnet-blazor-eng /src/Security/ @tratcher /src/Security/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review @tratcher -/src/Servers/ @tratcher @halter73 @BrennanConroy -/src/Servers/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review @tratcher @halter73 @BrennanConroy +/src/Servers/ @tratcher @halter73 @BrennanConroy @JamesNK +/src/Servers/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review @tratcher @halter73 @BrennanConroy @JamesNK /src/Shared/runtime/ @dotnet/http /src/Shared/test/Shared.Tests/runtime/ @dotnet/http /src/SignalR/ @BrennanConroy @halter73 diff --git a/eng/Build.props b/eng/Build.props index 8ca48331c8..a39342be7d 100644 --- a/eng/Build.props +++ b/eng/Build.props @@ -98,23 +98,17 @@ <!-- Build the SharedFramework installers --> <ProjectToBuild Include="$(RepoRoot)src\Installers\Windows\SharedFrameworkBundle\SharedFrameworkBundle.wixproj" AdditionalProperties="Platform=x64" /> <ProjectToBuild Include="$(RepoRoot)src\Installers\Windows\SharedFrameworkBundle\SharedFrameworkBundle.wixproj" AdditionalProperties="Platform=x86" /> + <ProjectToBuild Include="$(RepoRoot)src\Installers\Windows\SharedFrameworkBundle\SharedFrameworkBundle.wixproj" AdditionalProperties="Platform=arm64" /> <!-- Build the SharedFramework wixlib --> <ProjectToBuild Include="$(RepoRoot)src\Installers\Windows\SharedFrameworkLib\SharedFrameworkLib.wixproj" AdditionalProperties="Platform=x64" /> <ProjectToBuild Include="$(RepoRoot)src\Installers\Windows\SharedFrameworkLib\SharedFrameworkLib.wixproj" AdditionalProperties="Platform=x86" /> + <ProjectToBuild Include="$(RepoRoot)src\Installers\Windows\SharedFrameworkLib\SharedFrameworkLib.wixproj" AdditionalProperties="Platform=arm64" /> <!-- Windows hosting bundled --> <ProjectToBuild Include="$(RepoRoot)src\Installers\Windows\WindowsHostingBundle\WindowsHostingBundle.wixproj" AdditionalProperties="Platform=x86" /> </ItemGroup> - <ItemGroup Condition=" '$(BuildInstallers)' == 'true' AND '$(TargetOsName)' == 'win' AND '$(TargetArchitecture)' == 'arm64' "> - <!-- We don't build the targeting pack installer here because it's built in the x86/x64 leg. - Instead we only provide the ARM64 SharedFramework MSI--> - - <!-- Build the SharedFramework wixlib --> - <ProjectToBuild Include="$(RepoRoot)src\Installers\Windows\SharedFrameworkLib\SharedFrameworkLib.wixproj" AdditionalProperties="Platform=arm64" /> - </ItemGroup> - <ItemGroup Condition="'$(BuildInstallers)' == 'true' AND ('$(TargetRuntimeIdentifier)' == 'linux-x64' OR '$(TargetRuntimeIdentifier)' == 'linux-arm64')"> <ProjectToBuild Condition=" '$(LinuxInstallerType)' == 'deb' " Include="$(RepoRoot)src\Installers\Debian\**\*.*proj" /> diff --git a/eng/Publishing.props b/eng/Publishing.props index a812c9e293..ef4fe67705 100644 --- a/eng/Publishing.props +++ b/eng/Publishing.props @@ -97,10 +97,11 @@ Condition=" '$(PublishInstallerBaseVersion)' == 'true'"> <!-- This target is defined in eng/targets/Packaging.targets and Npm.Common.targets and included in every C#, F#, - and npm project. We use Microsoft.AspNetCore.App.Runtime.csproj because it is shipping (we need a stable - version string to use for productVersion.txt). + and npm project. We use Microsoft.JSInterop.JS.npmproj because it is shipping (we need a stable + version string to use for productVersion.txt), and because it won't break when the SDK requires a newer + desktop MSBuild than exists on the build machine. --> - <MSBuild Projects="$(RepoRoot)src\Framework\App.Runtime\src\Microsoft.AspNetCore.App.Runtime.csproj" + <MSBuild Projects="$(RepoRoot)src\JSInterop\Microsoft.JSInterop.JS\src\Microsoft.JSInterop.JS.npmproj" Properties="DisableYarnCheck=true;ExcludeFromBuild=false" Targets="_GetPackageVersionInfo"> <Output TaskParameter="TargetOutputs" ItemName="_ResolvedProductVersionInfo" /> diff --git a/eng/TrimmableProjects.props b/eng/TrimmableProjects.props index bbba1c4c17..f6db6bf40d 100644 --- a/eng/TrimmableProjects.props +++ b/eng/TrimmableProjects.props @@ -7,10 +7,14 @@ --> <Project> <ItemGroup> + <TrimmableProject Include="Microsoft.AspNetCore.Hosting.Abstractions" /> + <TrimmableProject Include="Microsoft.AspNetCore.Hosting.Server.Abstractions" /> <TrimmableProject Include="Microsoft.Net.Http.Headers" /> <TrimmableProject Include="Microsoft.AspNetCore.Http.Abstractions" /> + <TrimmableProject Include="Microsoft.AspNetCore.Http.Extensions" /> <TrimmableProject Include="Microsoft.AspNetCore.Http.Features" /> <TrimmableProject Include="Microsoft.AspNetCore.Metadata" /> + <TrimmableProject Include="Microsoft.AspNetCore.Routing.Abstractions" /> <TrimmableProject Include="Microsoft.AspNetCore.WebUtilities" /> <TrimmableProject Include="Microsoft.AspNetCore.Authorization" /> <TrimmableProject Include="Microsoft.AspNetCore.Components.Authorization" /> diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 14bccb3101..537cd2a378 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -9,301 +9,301 @@ --> <Dependencies> <ProductDependencies> - <Dependency Name="dotnet-ef" Version="7.0.0-preview.4.22173.5"> + <Dependency Name="dotnet-ef" Version="7.0.0-preview.4.22178.2"> <Uri>https://github.com/dotnet/efcore</Uri> - <Sha>12bcdbdffbfbbda9226ddeea54adba7605601c37</Sha> + <Sha>b7fefcae719b05c51d149f458a1fbca009a3cbf8</Sha> </Dependency> - <Dependency Name="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.0-preview.4.22173.5"> + <Dependency Name="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.0-preview.4.22178.2"> <Uri>https://github.com/dotnet/efcore</Uri> - <Sha>12bcdbdffbfbbda9226ddeea54adba7605601c37</Sha> + <Sha>b7fefcae719b05c51d149f458a1fbca009a3cbf8</Sha> </Dependency> - <Dependency Name="Microsoft.EntityFrameworkCore.Relational" Version="7.0.0-preview.4.22173.5"> + <Dependency Name="Microsoft.EntityFrameworkCore.Relational" Version="7.0.0-preview.4.22178.2"> <Uri>https://github.com/dotnet/efcore</Uri> - <Sha>12bcdbdffbfbbda9226ddeea54adba7605601c37</Sha> + <Sha>b7fefcae719b05c51d149f458a1fbca009a3cbf8</Sha> </Dependency> - <Dependency Name="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.0-preview.4.22173.5"> + <Dependency Name="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.0-preview.4.22178.2"> <Uri>https://github.com/dotnet/efcore</Uri> - <Sha>12bcdbdffbfbbda9226ddeea54adba7605601c37</Sha> + <Sha>b7fefcae719b05c51d149f458a1fbca009a3cbf8</Sha> </Dependency> - <Dependency Name="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0-preview.4.22173.5"> + <Dependency Name="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0-preview.4.22178.2"> <Uri>https://github.com/dotnet/efcore</Uri> - <Sha>12bcdbdffbfbbda9226ddeea54adba7605601c37</Sha> + <Sha>b7fefcae719b05c51d149f458a1fbca009a3cbf8</Sha> </Dependency> - <Dependency Name="Microsoft.EntityFrameworkCore.Tools" Version="7.0.0-preview.4.22173.5"> + <Dependency Name="Microsoft.EntityFrameworkCore.Tools" Version="7.0.0-preview.4.22178.2"> <Uri>https://github.com/dotnet/efcore</Uri> - <Sha>12bcdbdffbfbbda9226ddeea54adba7605601c37</Sha> + <Sha>b7fefcae719b05c51d149f458a1fbca009a3cbf8</Sha> </Dependency> - <Dependency Name="Microsoft.EntityFrameworkCore" Version="7.0.0-preview.4.22173.5"> + <Dependency Name="Microsoft.EntityFrameworkCore" Version="7.0.0-preview.4.22178.2"> <Uri>https://github.com/dotnet/efcore</Uri> - <Sha>12bcdbdffbfbbda9226ddeea54adba7605601c37</Sha> + <Sha>b7fefcae719b05c51d149f458a1fbca009a3cbf8</Sha> </Dependency> - <Dependency Name="Microsoft.EntityFrameworkCore.Design" Version="7.0.0-preview.4.22173.5"> + <Dependency Name="Microsoft.EntityFrameworkCore.Design" Version="7.0.0-preview.4.22178.2"> <Uri>https://github.com/dotnet/efcore</Uri> - <Sha>12bcdbdffbfbbda9226ddeea54adba7605601c37</Sha> + <Sha>b7fefcae719b05c51d149f458a1fbca009a3cbf8</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Caching.Abstractions" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Caching.Abstractions" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Caching.Memory" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Caching.Memory" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Configuration.Abstractions" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Configuration.Abstractions" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Configuration.Binder" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Configuration.Binder" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Configuration.CommandLine" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Configuration.CommandLine" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Configuration.FileExtensions" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Configuration.FileExtensions" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Configuration.Ini" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Configuration.Ini" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Configuration.Json" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Configuration.Json" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Configuration.Xml" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Configuration.Xml" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Configuration" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Configuration" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.DependencyInjection" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.DependencyInjection" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.FileProviders.Abstractions" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.FileProviders.Abstractions" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.FileProviders.Composite" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.FileProviders.Composite" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.FileProviders.Physical" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.FileProviders.Physical" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.FileSystemGlobbing" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.FileSystemGlobbing" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.HostFactoryResolver.Sources" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.HostFactoryResolver.Sources" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Hosting.Abstractions" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Hosting.Abstractions" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Hosting" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Hosting" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Http" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Http" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Logging.Configuration" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Logging.Configuration" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Logging.Console" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Logging.Console" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Logging.Debug" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Logging.Debug" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Logging.EventSource" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Logging.EventSource" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Logging.EventLog" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Logging.EventLog" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Logging.TraceSource" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Logging.TraceSource" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Logging" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Logging" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Options.ConfigurationExtensions" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Options.ConfigurationExtensions" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Options.DataAnnotations" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Options.DataAnnotations" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Options" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Options" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.Primitives" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.Primitives" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Internal.Runtime.AspNetCore.Transport" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Internal.Runtime.AspNetCore.Transport" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="System.Diagnostics.DiagnosticSource" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="System.Diagnostics.DiagnosticSource" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="System.Diagnostics.EventLog" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="System.Diagnostics.EventLog" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="System.DirectoryServices.Protocols" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="System.DirectoryServices.Protocols" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="System.IO.Pipelines" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="System.IO.Pipelines" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="System.Net.Http.Json" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="System.Net.Http.Json" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="System.Net.Http.WinHttpHandler" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="System.Net.Http.WinHttpHandler" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="System.Reflection.Metadata" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="System.Reflection.Metadata" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="System.Resources.Extensions" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="System.Resources.Extensions" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="System.Security.Cryptography.Pkcs" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="System.Security.Cryptography.Pkcs" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="System.Security.Cryptography.Xml" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="System.Security.Cryptography.Xml" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="System.Security.Permissions" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="System.Security.Permissions" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="System.ServiceProcess.ServiceController" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="System.ServiceProcess.ServiceController" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="System.Text.Encodings.Web" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="System.Text.Encodings.Web" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="System.Text.Json" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="System.Text.Json" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="System.Threading.AccessControl" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="System.Threading.AccessControl" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="System.Threading.Channels" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="System.Threading.Channels" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="System.Threading.RateLimiting" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="System.Threading.RateLimiting" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.Extensions.DependencyModel" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.Extensions.DependencyModel" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.NETCore.App.Ref" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.NETCore.App.Ref" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.NET.Runtime.MonoAOTCompiler.Task" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.NET.Runtime.MonoAOTCompiler.Task" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.NET.Runtime.WebAssembly.Sdk" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.NET.Runtime.WebAssembly.Sdk" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> <!-- Win-x64 is used here because we have picked an arbitrary runtime identifier to flow the version of the latest NETCore.App runtime. All Runtime.$rid packages should have the same version. --> - <Dependency Name="Microsoft.NETCore.App.Runtime.win-x64" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.NETCore.App.Runtime.win-x64" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.NETCore.App.Runtime.AOT.win-x64.Cross.browser-wasm" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.NETCore.App.Runtime.AOT.win-x64.Cross.browser-wasm" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.NETCore.BrowserDebugHost.Transport" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.NETCore.BrowserDebugHost.Transport" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> </ProductDependencies> <ToolsetDependencies> <!-- Listed explicitly to workaround https://github.com/dotnet/cli/issues/10528 --> - <Dependency Name="Microsoft.NETCore.Platforms" Version="7.0.0-preview.4.22174.7"> + <Dependency Name="Microsoft.NETCore.Platforms" Version="7.0.0-preview.4.22180.7"> <Uri>https://github.com/dotnet/runtime</Uri> - <Sha>cd5beb14b0ce11ae1e4e3f1d30bffba7e37ce606</Sha> + <Sha>c0db07b3f3f093b5f4cd27e1f5e8aa54adad049d</Sha> </Dependency> - <Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="7.0.0-beta.22168.2"> + <Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="7.0.0-beta.22171.2"> <Uri>https://github.com/dotnet/arcade</Uri> - <Sha>bafd55901b50d6fc3507c8ed96a7777fcca1796f</Sha> + <Sha>c8a95297e2622251c125aa5c0ef7c822275a792d</Sha> <SourceBuild RepoName="arcade" ManagedOnly="true" /> </Dependency> - <Dependency Name="Microsoft.DotNet.Build.Tasks.Installers" Version="7.0.0-beta.22168.2"> + <Dependency Name="Microsoft.DotNet.Build.Tasks.Installers" Version="7.0.0-beta.22171.2"> <Uri>https://github.com/dotnet/arcade</Uri> - <Sha>bafd55901b50d6fc3507c8ed96a7777fcca1796f</Sha> + <Sha>c8a95297e2622251c125aa5c0ef7c822275a792d</Sha> </Dependency> - <Dependency Name="Microsoft.DotNet.Build.Tasks.Templating" Version="7.0.0-beta.22168.2"> + <Dependency Name="Microsoft.DotNet.Build.Tasks.Templating" Version="7.0.0-beta.22171.2"> <Uri>https://github.com/dotnet/arcade</Uri> - <Sha>bafd55901b50d6fc3507c8ed96a7777fcca1796f</Sha> + <Sha>c8a95297e2622251c125aa5c0ef7c822275a792d</Sha> </Dependency> - <Dependency Name="Microsoft.DotNet.Helix.Sdk" Version="7.0.0-beta.22168.2"> + <Dependency Name="Microsoft.DotNet.Helix.Sdk" Version="7.0.0-beta.22171.2"> <Uri>https://github.com/dotnet/arcade</Uri> - <Sha>bafd55901b50d6fc3507c8ed96a7777fcca1796f</Sha> + <Sha>c8a95297e2622251c125aa5c0ef7c822275a792d</Sha> </Dependency> </ToolsetDependencies> </Dependencies> diff --git a/eng/Versions.props b/eng/Versions.props index 6ceb8c6243..8f2faf555e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -63,79 +63,79 @@ --> <PropertyGroup Label="Automated"> <!-- Packages from dotnet/runtime --> - <MicrosoftExtensionsDependencyModelVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsDependencyModelVersion> - <MicrosoftNETCoreAppRefVersion>7.0.0-preview.4.22174.7</MicrosoftNETCoreAppRefVersion> - <MicrosoftNETCoreAppRuntimewinx64Version>7.0.0-preview.4.22174.7</MicrosoftNETCoreAppRuntimewinx64Version> - <MicrosoftNETRuntimeMonoAOTCompilerTaskVersion>7.0.0-preview.4.22174.7</MicrosoftNETRuntimeMonoAOTCompilerTaskVersion> - <MicrosoftNETRuntimeWebAssemblySdkVersion>7.0.0-preview.4.22174.7</MicrosoftNETRuntimeWebAssemblySdkVersion> - <MicrosoftNETCoreAppRuntimeAOTwinx64CrossbrowserwasmVersion>7.0.0-preview.4.22174.7</MicrosoftNETCoreAppRuntimeAOTwinx64CrossbrowserwasmVersion> - <MicrosoftNETCoreBrowserDebugHostTransportVersion>7.0.0-preview.4.22174.7</MicrosoftNETCoreBrowserDebugHostTransportVersion> - <MicrosoftExtensionsCachingAbstractionsVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsCachingAbstractionsVersion> - <MicrosoftExtensionsCachingMemoryVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsCachingMemoryVersion> - <MicrosoftExtensionsConfigurationAbstractionsVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsConfigurationAbstractionsVersion> - <MicrosoftExtensionsConfigurationBinderVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsConfigurationBinderVersion> - <MicrosoftExtensionsConfigurationCommandLineVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsConfigurationCommandLineVersion> - <MicrosoftExtensionsConfigurationEnvironmentVariablesVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsConfigurationEnvironmentVariablesVersion> - <MicrosoftExtensionsConfigurationFileExtensionsVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsConfigurationFileExtensionsVersion> - <MicrosoftExtensionsConfigurationIniVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsConfigurationIniVersion> - <MicrosoftExtensionsConfigurationJsonVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsConfigurationJsonVersion> - <MicrosoftExtensionsConfigurationVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsConfigurationVersion> - <MicrosoftExtensionsConfigurationUserSecretsVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsConfigurationUserSecretsVersion> - <MicrosoftExtensionsConfigurationXmlVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsConfigurationXmlVersion> - <MicrosoftExtensionsDependencyInjectionAbstractionsVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsDependencyInjectionAbstractionsVersion> - <MicrosoftExtensionsDependencyInjectionVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsDependencyInjectionVersion> - <MicrosoftExtensionsFileProvidersAbstractionsVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsFileProvidersAbstractionsVersion> - <MicrosoftExtensionsFileProvidersCompositeVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsFileProvidersCompositeVersion> - <MicrosoftExtensionsFileProvidersPhysicalVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsFileProvidersPhysicalVersion> - <MicrosoftExtensionsFileSystemGlobbingVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsFileSystemGlobbingVersion> - <MicrosoftExtensionsHostFactoryResolverSourcesVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsHostFactoryResolverSourcesVersion> - <MicrosoftExtensionsHostingAbstractionsVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsHostingAbstractionsVersion> - <MicrosoftExtensionsHostingVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsHostingVersion> - <MicrosoftExtensionsHttpVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsHttpVersion> - <MicrosoftExtensionsLoggingAbstractionsVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsLoggingAbstractionsVersion> - <MicrosoftExtensionsLoggingConfigurationVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsLoggingConfigurationVersion> - <MicrosoftExtensionsLoggingConsoleVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsLoggingConsoleVersion> - <MicrosoftExtensionsLoggingDebugVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsLoggingDebugVersion> - <MicrosoftExtensionsLoggingEventSourceVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsLoggingEventSourceVersion> - <MicrosoftExtensionsLoggingEventLogVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsLoggingEventLogVersion> - <MicrosoftExtensionsLoggingVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsLoggingVersion> - <MicrosoftExtensionsLoggingTraceSourceVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsLoggingTraceSourceVersion> - <MicrosoftExtensionsOptionsConfigurationExtensionsVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsOptionsConfigurationExtensionsVersion> - <MicrosoftExtensionsOptionsDataAnnotationsVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsOptionsDataAnnotationsVersion> - <MicrosoftExtensionsOptionsVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsOptionsVersion> - <MicrosoftExtensionsPrimitivesVersion>7.0.0-preview.4.22174.7</MicrosoftExtensionsPrimitivesVersion> - <MicrosoftInternalRuntimeAspNetCoreTransportVersion>7.0.0-preview.4.22174.7</MicrosoftInternalRuntimeAspNetCoreTransportVersion> - <SystemDiagnosticsDiagnosticSourceVersion>7.0.0-preview.4.22174.7</SystemDiagnosticsDiagnosticSourceVersion> - <SystemDiagnosticsEventLogVersion>7.0.0-preview.4.22174.7</SystemDiagnosticsEventLogVersion> - <SystemDirectoryServicesProtocolsVersion>7.0.0-preview.4.22174.7</SystemDirectoryServicesProtocolsVersion> - <SystemIOPipelinesVersion>7.0.0-preview.4.22174.7</SystemIOPipelinesVersion> - <SystemNetHttpJsonVersion>7.0.0-preview.4.22174.7</SystemNetHttpJsonVersion> - <SystemNetHttpWinHttpHandlerVersion>7.0.0-preview.4.22174.7</SystemNetHttpWinHttpHandlerVersion> - <SystemReflectionMetadataVersion>7.0.0-preview.4.22174.7</SystemReflectionMetadataVersion> - <SystemResourcesExtensionsVersion>7.0.0-preview.4.22174.7</SystemResourcesExtensionsVersion> - <SystemSecurityCryptographyPkcsVersion>7.0.0-preview.4.22174.7</SystemSecurityCryptographyPkcsVersion> - <SystemSecurityCryptographyXmlVersion>7.0.0-preview.4.22174.7</SystemSecurityCryptographyXmlVersion> - <SystemSecurityPermissionsVersion>7.0.0-preview.4.22174.7</SystemSecurityPermissionsVersion> - <SystemServiceProcessServiceControllerVersion>7.0.0-preview.4.22174.7</SystemServiceProcessServiceControllerVersion> - <SystemTextEncodingsWebVersion>7.0.0-preview.4.22174.7</SystemTextEncodingsWebVersion> - <SystemTextJsonVersion>7.0.0-preview.4.22174.7</SystemTextJsonVersion> - <SystemThreadingAccessControlVersion>7.0.0-preview.4.22174.7</SystemThreadingAccessControlVersion> - <SystemThreadingChannelsVersion>7.0.0-preview.4.22174.7</SystemThreadingChannelsVersion> - <SystemThreadingRateLimitingVersion>7.0.0-preview.4.22174.7</SystemThreadingRateLimitingVersion> + <MicrosoftExtensionsDependencyModelVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsDependencyModelVersion> + <MicrosoftNETCoreAppRefVersion>7.0.0-preview.4.22180.7</MicrosoftNETCoreAppRefVersion> + <MicrosoftNETCoreAppRuntimewinx64Version>7.0.0-preview.4.22180.7</MicrosoftNETCoreAppRuntimewinx64Version> + <MicrosoftNETRuntimeMonoAOTCompilerTaskVersion>7.0.0-preview.4.22180.7</MicrosoftNETRuntimeMonoAOTCompilerTaskVersion> + <MicrosoftNETRuntimeWebAssemblySdkVersion>7.0.0-preview.4.22180.7</MicrosoftNETRuntimeWebAssemblySdkVersion> + <MicrosoftNETCoreAppRuntimeAOTwinx64CrossbrowserwasmVersion>7.0.0-preview.4.22180.7</MicrosoftNETCoreAppRuntimeAOTwinx64CrossbrowserwasmVersion> + <MicrosoftNETCoreBrowserDebugHostTransportVersion>7.0.0-preview.4.22180.7</MicrosoftNETCoreBrowserDebugHostTransportVersion> + <MicrosoftExtensionsCachingAbstractionsVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsCachingAbstractionsVersion> + <MicrosoftExtensionsCachingMemoryVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsCachingMemoryVersion> + <MicrosoftExtensionsConfigurationAbstractionsVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsConfigurationAbstractionsVersion> + <MicrosoftExtensionsConfigurationBinderVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsConfigurationBinderVersion> + <MicrosoftExtensionsConfigurationCommandLineVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsConfigurationCommandLineVersion> + <MicrosoftExtensionsConfigurationEnvironmentVariablesVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsConfigurationEnvironmentVariablesVersion> + <MicrosoftExtensionsConfigurationFileExtensionsVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsConfigurationFileExtensionsVersion> + <MicrosoftExtensionsConfigurationIniVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsConfigurationIniVersion> + <MicrosoftExtensionsConfigurationJsonVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsConfigurationJsonVersion> + <MicrosoftExtensionsConfigurationVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsConfigurationVersion> + <MicrosoftExtensionsConfigurationUserSecretsVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsConfigurationUserSecretsVersion> + <MicrosoftExtensionsConfigurationXmlVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsConfigurationXmlVersion> + <MicrosoftExtensionsDependencyInjectionAbstractionsVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsDependencyInjectionAbstractionsVersion> + <MicrosoftExtensionsDependencyInjectionVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsDependencyInjectionVersion> + <MicrosoftExtensionsFileProvidersAbstractionsVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsFileProvidersAbstractionsVersion> + <MicrosoftExtensionsFileProvidersCompositeVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsFileProvidersCompositeVersion> + <MicrosoftExtensionsFileProvidersPhysicalVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsFileProvidersPhysicalVersion> + <MicrosoftExtensionsFileSystemGlobbingVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsFileSystemGlobbingVersion> + <MicrosoftExtensionsHostFactoryResolverSourcesVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsHostFactoryResolverSourcesVersion> + <MicrosoftExtensionsHostingAbstractionsVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsHostingAbstractionsVersion> + <MicrosoftExtensionsHostingVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsHostingVersion> + <MicrosoftExtensionsHttpVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsHttpVersion> + <MicrosoftExtensionsLoggingAbstractionsVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsLoggingAbstractionsVersion> + <MicrosoftExtensionsLoggingConfigurationVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsLoggingConfigurationVersion> + <MicrosoftExtensionsLoggingConsoleVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsLoggingConsoleVersion> + <MicrosoftExtensionsLoggingDebugVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsLoggingDebugVersion> + <MicrosoftExtensionsLoggingEventSourceVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsLoggingEventSourceVersion> + <MicrosoftExtensionsLoggingEventLogVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsLoggingEventLogVersion> + <MicrosoftExtensionsLoggingVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsLoggingVersion> + <MicrosoftExtensionsLoggingTraceSourceVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsLoggingTraceSourceVersion> + <MicrosoftExtensionsOptionsConfigurationExtensionsVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsOptionsConfigurationExtensionsVersion> + <MicrosoftExtensionsOptionsDataAnnotationsVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsOptionsDataAnnotationsVersion> + <MicrosoftExtensionsOptionsVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsOptionsVersion> + <MicrosoftExtensionsPrimitivesVersion>7.0.0-preview.4.22180.7</MicrosoftExtensionsPrimitivesVersion> + <MicrosoftInternalRuntimeAspNetCoreTransportVersion>7.0.0-preview.4.22180.7</MicrosoftInternalRuntimeAspNetCoreTransportVersion> + <SystemDiagnosticsDiagnosticSourceVersion>7.0.0-preview.4.22180.7</SystemDiagnosticsDiagnosticSourceVersion> + <SystemDiagnosticsEventLogVersion>7.0.0-preview.4.22180.7</SystemDiagnosticsEventLogVersion> + <SystemDirectoryServicesProtocolsVersion>7.0.0-preview.4.22180.7</SystemDirectoryServicesProtocolsVersion> + <SystemIOPipelinesVersion>7.0.0-preview.4.22180.7</SystemIOPipelinesVersion> + <SystemNetHttpJsonVersion>7.0.0-preview.4.22180.7</SystemNetHttpJsonVersion> + <SystemNetHttpWinHttpHandlerVersion>7.0.0-preview.4.22180.7</SystemNetHttpWinHttpHandlerVersion> + <SystemReflectionMetadataVersion>7.0.0-preview.4.22180.7</SystemReflectionMetadataVersion> + <SystemResourcesExtensionsVersion>7.0.0-preview.4.22180.7</SystemResourcesExtensionsVersion> + <SystemSecurityCryptographyPkcsVersion>7.0.0-preview.4.22180.7</SystemSecurityCryptographyPkcsVersion> + <SystemSecurityCryptographyXmlVersion>7.0.0-preview.4.22180.7</SystemSecurityCryptographyXmlVersion> + <SystemSecurityPermissionsVersion>7.0.0-preview.4.22180.7</SystemSecurityPermissionsVersion> + <SystemServiceProcessServiceControllerVersion>7.0.0-preview.4.22180.7</SystemServiceProcessServiceControllerVersion> + <SystemTextEncodingsWebVersion>7.0.0-preview.4.22180.7</SystemTextEncodingsWebVersion> + <SystemTextJsonVersion>7.0.0-preview.4.22180.7</SystemTextJsonVersion> + <SystemThreadingAccessControlVersion>7.0.0-preview.4.22180.7</SystemThreadingAccessControlVersion> + <SystemThreadingChannelsVersion>7.0.0-preview.4.22180.7</SystemThreadingChannelsVersion> + <SystemThreadingRateLimitingVersion>7.0.0-preview.4.22180.7</SystemThreadingRateLimitingVersion> <!-- Only listed explicitly to workaround https://github.com/dotnet/cli/issues/10528 --> - <MicrosoftNETCorePlatformsVersion>7.0.0-preview.4.22174.7</MicrosoftNETCorePlatformsVersion> + <MicrosoftNETCorePlatformsVersion>7.0.0-preview.4.22180.7</MicrosoftNETCorePlatformsVersion> <!-- Packages from dotnet/efcore --> - <dotnetefVersion>7.0.0-preview.4.22173.5</dotnetefVersion> - <MicrosoftEntityFrameworkCoreInMemoryVersion>7.0.0-preview.4.22173.5</MicrosoftEntityFrameworkCoreInMemoryVersion> - <MicrosoftEntityFrameworkCoreRelationalVersion>7.0.0-preview.4.22173.5</MicrosoftEntityFrameworkCoreRelationalVersion> - <MicrosoftEntityFrameworkCoreSqliteVersion>7.0.0-preview.4.22173.5</MicrosoftEntityFrameworkCoreSqliteVersion> - <MicrosoftEntityFrameworkCoreSqlServerVersion>7.0.0-preview.4.22173.5</MicrosoftEntityFrameworkCoreSqlServerVersion> - <MicrosoftEntityFrameworkCoreToolsVersion>7.0.0-preview.4.22173.5</MicrosoftEntityFrameworkCoreToolsVersion> - <MicrosoftEntityFrameworkCoreVersion>7.0.0-preview.4.22173.5</MicrosoftEntityFrameworkCoreVersion> - <MicrosoftEntityFrameworkCoreDesignVersion>7.0.0-preview.4.22173.5</MicrosoftEntityFrameworkCoreDesignVersion> + <dotnetefVersion>7.0.0-preview.4.22178.2</dotnetefVersion> + <MicrosoftEntityFrameworkCoreInMemoryVersion>7.0.0-preview.4.22178.2</MicrosoftEntityFrameworkCoreInMemoryVersion> + <MicrosoftEntityFrameworkCoreRelationalVersion>7.0.0-preview.4.22178.2</MicrosoftEntityFrameworkCoreRelationalVersion> + <MicrosoftEntityFrameworkCoreSqliteVersion>7.0.0-preview.4.22178.2</MicrosoftEntityFrameworkCoreSqliteVersion> + <MicrosoftEntityFrameworkCoreSqlServerVersion>7.0.0-preview.4.22178.2</MicrosoftEntityFrameworkCoreSqlServerVersion> + <MicrosoftEntityFrameworkCoreToolsVersion>7.0.0-preview.4.22178.2</MicrosoftEntityFrameworkCoreToolsVersion> + <MicrosoftEntityFrameworkCoreVersion>7.0.0-preview.4.22178.2</MicrosoftEntityFrameworkCoreVersion> + <MicrosoftEntityFrameworkCoreDesignVersion>7.0.0-preview.4.22178.2</MicrosoftEntityFrameworkCoreDesignVersion> <!-- Packages from dotnet/arcade --> - <MicrosoftDotNetBuildTasksInstallersVersion>7.0.0-beta.22168.2</MicrosoftDotNetBuildTasksInstallersVersion> - <MicrosoftDotNetBuildTasksTemplatingVersion>7.0.0-beta.22168.2</MicrosoftDotNetBuildTasksTemplatingVersion> + <MicrosoftDotNetBuildTasksInstallersVersion>7.0.0-beta.22171.2</MicrosoftDotNetBuildTasksInstallersVersion> + <MicrosoftDotNetBuildTasksTemplatingVersion>7.0.0-beta.22171.2</MicrosoftDotNetBuildTasksTemplatingVersion> </PropertyGroup> <!-- diff --git a/eng/helix/content/runtests.sh b/eng/helix/content/runtests.sh index 1fd36f1997..af91c928ab 100644 --- a/eng/helix/content/runtests.sh +++ b/eng/helix/content/runtests.sh @@ -76,7 +76,16 @@ sync exit_code=0 echo "Restore: dotnet restore RunTests/RunTests.csproj --ignore-failed-sources" -dotnet restore RunTests/RunTests.csproj --ignore-failed-sources + +# --verbosity diagnostic can be removed when random failures are identified +dotnet restore RunTests/RunTests.csproj --ignore-failed-sources --verbosity diagnostic + +exit_code=$? + +if [[ $exit_code != 0 ]]; then + echo "Restore runtests failed: exit_code=$exit_code" + exit $exit_code +fi echo "Running tests: dotnet run --no-restore --project RunTests/RunTests.csproj -- --target $1 --runtime $2 --queue $helixQueue --arch $4 --quarantined $5 --ef $6 --helixTimeout $7" dotnet run --no-restore --project RunTests/RunTests.csproj -- --target $1 --runtime $2 --queue $helixQueue --arch $4 --quarantined $5 --ef $6 --helixTimeout $7 diff --git a/global.json b/global.json index fdb8f88394..daef57c601 100644 --- a/global.json +++ b/global.json @@ -1,9 +1,9 @@ { "sdk": { - "version": "7.0.100-preview.4.22174.1" + "version": "7.0.100-preview.4.22175.5" }, "tools": { - "dotnet": "7.0.100-preview.4.22174.1", + "dotnet": "7.0.100-preview.4.22175.5", "runtimes": { "dotnet/x86": [ "$(MicrosoftNETCoreBrowserDebugHostTransportVersion)" @@ -27,7 +27,7 @@ }, "msbuild-sdks": { "Yarn.MSBuild": "1.22.10", - "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.22168.2", - "Microsoft.DotNet.Helix.Sdk": "7.0.0-beta.22168.2" + "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.22171.2", + "Microsoft.DotNet.Helix.Sdk": "7.0.0-beta.22171.2" } } diff --git a/src/Caching/SqlServer/src/MonoDatabaseOperations.cs b/src/Caching/SqlServer/src/MonoDatabaseOperations.cs deleted file mode 100644 index 694a59c46a..0000000000 --- a/src/Caching/SqlServer/src/MonoDatabaseOperations.cs +++ /dev/null @@ -1,201 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Data; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Data.SqlClient; -using Microsoft.Extensions.Caching.Distributed; -using Microsoft.Extensions.Internal; - -namespace Microsoft.Extensions.Caching.SqlServer; - -internal class MonoDatabaseOperations : DatabaseOperations -{ - public MonoDatabaseOperations( - string connectionString, string schemaName, string tableName, ISystemClock systemClock) - : base(connectionString, schemaName, tableName, systemClock) - { - } - - protected override byte[]? GetCacheItem(string key, bool includeValue) - { - var utcNow = SystemClock.UtcNow; - - string query; - if (includeValue) - { - query = SqlQueries.GetCacheItem; - } - else - { - query = SqlQueries.GetCacheItemWithoutValue; - } - - byte[]? value = null; - using (var connection = new SqlConnection(ConnectionString)) - { - var command = new SqlCommand(query, connection); - command.Parameters - .AddCacheItemId(key) - .AddWithValue("UtcNow", SqlDbType.DateTime, utcNow.UtcDateTime); - - connection.Open(); - - var reader = command.ExecuteReader(CommandBehavior.SingleRow | CommandBehavior.SingleResult); - - if (reader.Read()) - { - if (includeValue) - { - value = (byte[])reader[Columns.Indexes.CacheItemValueIndex]; - } - } - else - { - return null; - } - } - - return value; - } - - protected override async Task<byte[]?> GetCacheItemAsync(string key, bool includeValue, CancellationToken token = default(CancellationToken)) - { - token.ThrowIfCancellationRequested(); - - var utcNow = SystemClock.UtcNow; - - string query; - if (includeValue) - { - query = SqlQueries.GetCacheItem; - } - else - { - query = SqlQueries.GetCacheItemWithoutValue; - } - - byte[]? value = null; - using (var connection = new SqlConnection(ConnectionString)) - { - var command = new SqlCommand(query, connection); - command.Parameters - .AddCacheItemId(key) - .AddWithValue("UtcNow", SqlDbType.DateTime, utcNow.UtcDateTime); - - await connection.OpenAsync(token).ConfigureAwait(false); - - var reader = await command.ExecuteReaderAsync( - CommandBehavior.SingleRow | CommandBehavior.SingleResult, - token).ConfigureAwait(false); - - if (await reader.ReadAsync(token).ConfigureAwait(false)) - { - if (includeValue) - { - value = (byte[])reader[Columns.Indexes.CacheItemValueIndex]; - } - } - else - { - return null; - } - } - - return value; - } - - public override void SetCacheItem(string key, byte[] value, DistributedCacheEntryOptions options) - { - var utcNow = SystemClock.UtcNow; - - var absoluteExpiration = DatabaseOperations.GetAbsoluteExpiration(utcNow, options); - DatabaseOperations.ValidateOptions(options.SlidingExpiration, absoluteExpiration); - - using (var connection = new SqlConnection(ConnectionString)) - { - var upsertCommand = new SqlCommand(SqlQueries.SetCacheItem, connection); - upsertCommand.Parameters - .AddCacheItemId(key) - .AddCacheItemValue(value) - .AddSlidingExpirationInSeconds(options.SlidingExpiration) - .AddAbsoluteExpirationMono(absoluteExpiration) - .AddWithValue("UtcNow", SqlDbType.DateTime, utcNow.UtcDateTime); - - connection.Open(); - - try - { - upsertCommand.ExecuteNonQuery(); - } - catch (SqlException ex) - { - if (DatabaseOperations.IsDuplicateKeyException(ex)) - { - // There is a possibility that multiple requests can try to add the same item to the cache, in - // which case we receive a 'duplicate key' exception on the primary key column. - } - else - { - throw; - } - } - } - } - - public override async Task SetCacheItemAsync(string key, byte[] value, DistributedCacheEntryOptions options, CancellationToken token = default(CancellationToken)) - { - token.ThrowIfCancellationRequested(); - - var utcNow = SystemClock.UtcNow; - - var absoluteExpiration = DatabaseOperations.GetAbsoluteExpiration(utcNow, options); - DatabaseOperations.ValidateOptions(options.SlidingExpiration, absoluteExpiration); - - using (var connection = new SqlConnection(ConnectionString)) - { - var upsertCommand = new SqlCommand(SqlQueries.SetCacheItem, connection); - upsertCommand.Parameters - .AddCacheItemId(key) - .AddCacheItemValue(value) - .AddSlidingExpirationInSeconds(options.SlidingExpiration) - .AddAbsoluteExpirationMono(absoluteExpiration) - .AddWithValue("UtcNow", SqlDbType.DateTime, utcNow.UtcDateTime); - - await connection.OpenAsync(token).ConfigureAwait(false); - - try - { - await upsertCommand.ExecuteNonQueryAsync(token).ConfigureAwait(false); - } - catch (SqlException ex) - { - if (DatabaseOperations.IsDuplicateKeyException(ex)) - { - // There is a possibility that multiple requests can try to add the same item to the cache, in - // which case we receive a 'duplicate key' exception on the primary key column. - } - else - { - throw; - } - } - } - } - - public override void DeleteExpiredCacheItems() - { - var utcNow = SystemClock.UtcNow; - - using (var connection = new SqlConnection(ConnectionString)) - { - var command = new SqlCommand(SqlQueries.DeleteExpiredCacheItems, connection); - command.Parameters.AddWithValue("UtcNow", SqlDbType.DateTime, utcNow.UtcDateTime); - - connection.Open(); - - var effectedRowCount = command.ExecuteNonQuery(); - } - } -} diff --git a/src/Caching/SqlServer/src/MonoSqlParameterCollectionExtensions.cs b/src/Caching/SqlServer/src/MonoSqlParameterCollectionExtensions.cs deleted file mode 100644 index 96e896912a..0000000000 --- a/src/Caching/SqlServer/src/MonoSqlParameterCollectionExtensions.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Data; -using Microsoft.Data.SqlClient; - -namespace Microsoft.Extensions.Caching.SqlServer; - -// Since Mono currently does not have support for DateTimeOffset, we convert the time to UtcDateTime. -// Even though the database column is of type 'datetimeoffset', we can store the UtcDateTime, in which case -// the zone is set as 00:00. If you look at the below examples, DateTimeOffset.UtcNow -// and DateTimeOffset.UtcDateTime are almost the same. -// -// Examples: -// DateTimeOffset.Now: 6/29/2015 1:20:40 PM - 07:00 -// DateTimeOffset.UtcNow: 6/29/2015 8:20:40 PM + 00:00 -// DateTimeOffset.UtcDateTime: 6/29/2015 8:20:40 PM -internal static class MonoSqlParameterCollectionExtensions -{ - public static SqlParameterCollection AddExpiresAtTimeMono( - this SqlParameterCollection parameters, - DateTimeOffset utcTime) - { - return parameters.AddWithValue(Columns.Names.ExpiresAtTime, SqlDbType.DateTime, utcTime.UtcDateTime); - } - - public static SqlParameterCollection AddAbsoluteExpirationMono( - this SqlParameterCollection parameters, - DateTimeOffset? utcTime) - { - if (utcTime.HasValue) - { - return parameters.AddWithValue( - Columns.Names.AbsoluteExpiration, SqlDbType.DateTime, utcTime.Value.UtcDateTime); - } - else - { - return parameters.AddWithValue( - Columns.Names.AbsoluteExpiration, SqlDbType.DateTime, DBNull.Value); - } - } -} diff --git a/src/Caching/SqlServer/src/PlatformHelper.cs b/src/Caching/SqlServer/src/PlatformHelper.cs deleted file mode 100644 index 613b98d7b5..0000000000 --- a/src/Caching/SqlServer/src/PlatformHelper.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; - -namespace Microsoft.Extensions.Caching.SqlServer; - -internal static class PlatformHelper -{ - private static readonly Lazy<bool> _isMono = new Lazy<bool>(() => Type.GetType("Mono.Runtime") != null); - - public static bool IsMono - { - get - { - return _isMono.Value; - } - } -} diff --git a/src/Caching/SqlServer/src/SqlServerCache.cs b/src/Caching/SqlServer/src/SqlServerCache.cs index bc22e2a6fd..968dbb8430 100644 --- a/src/Caching/SqlServer/src/SqlServerCache.cs +++ b/src/Caching/SqlServer/src/SqlServerCache.cs @@ -70,25 +70,11 @@ public class SqlServerCache : IDistributedCache _deleteExpiredCachedItemsDelegate = DeleteExpiredCacheItems; _defaultSlidingExpiration = cacheOptions.DefaultSlidingExpiration; - // SqlClient library on Mono doesn't have support for DateTimeOffset and also - // it doesn't have support for apis like GetFieldValue, GetFieldValueAsync etc. - // So we detect the platform to perform things differently for Mono vs. non-Mono platforms. - if (PlatformHelper.IsMono) - { - _dbOperations = new MonoDatabaseOperations( - cacheOptions.ConnectionString, - cacheOptions.SchemaName, - cacheOptions.TableName, - _systemClock); - } - else - { - _dbOperations = new DatabaseOperations( - cacheOptions.ConnectionString, - cacheOptions.SchemaName, - cacheOptions.TableName, - _systemClock); - } + _dbOperations = new DatabaseOperations( + cacheOptions.ConnectionString, + cacheOptions.SchemaName, + cacheOptions.TableName, + _systemClock); } /// <inheritdoc /> diff --git a/src/Components/WebAssembly/Authentication.Msal/src/Interop/package.json b/src/Components/WebAssembly/Authentication.Msal/src/Interop/package.json index f3195a5a34..43862a4806 100644 --- a/src/Components/WebAssembly/Authentication.Msal/src/Interop/package.json +++ b/src/Components/WebAssembly/Authentication.Msal/src/Interop/package.json @@ -29,6 +29,7 @@ "@azure/msal-browser": "^2.16.1" }, "resolutions": { - "ansi-regex": "5.0.1" + "ansi-regex": "5.0.1", + "minimist": ">=1.2.6" } } diff --git a/src/Components/WebAssembly/Authentication.Msal/src/Interop/yarn.lock b/src/Components/WebAssembly/Authentication.Msal/src/Interop/yarn.lock index 51b9f4e1bf..97ffee2210 100644 --- a/src/Components/WebAssembly/Authentication.Msal/src/Interop/yarn.lock +++ b/src/Components/WebAssembly/Authentication.Msal/src/Interop/yarn.lock @@ -2168,10 +2168,10 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +minimist@>=1.2.6, minimist@^1.2.5: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== ms@2.1.2: version "2.1.2" diff --git a/src/Components/WebAssembly/WebAssembly.Authentication/src/Interop/package.json b/src/Components/WebAssembly/WebAssembly.Authentication/src/Interop/package.json index 09ce7e5b8b..c93a4112fb 100644 --- a/src/Components/WebAssembly/WebAssembly.Authentication/src/Interop/package.json +++ b/src/Components/WebAssembly/WebAssembly.Authentication/src/Interop/package.json @@ -29,6 +29,7 @@ "oidc-client": "^1.11.5" }, "resolutions": { - "ansi-regex": "5.0.1" + "ansi-regex": "5.0.1", + "minimist": ">=1.2.6" } } diff --git a/src/Components/WebAssembly/WebAssembly.Authentication/src/Interop/yarn.lock b/src/Components/WebAssembly/WebAssembly.Authentication/src/Interop/yarn.lock index 6c69bb84ab..5b524eaca4 100644 --- a/src/Components/WebAssembly/WebAssembly.Authentication/src/Interop/yarn.lock +++ b/src/Components/WebAssembly/WebAssembly.Authentication/src/Interop/yarn.lock @@ -2169,10 +2169,10 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +minimist@>=1.2.6, minimist@^1.2.5: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== ms@2.1.2: version "2.1.2" diff --git a/src/Components/WebView/WebView/src/Services/WebViewJSRuntime.cs b/src/Components/WebView/WebView/src/Services/WebViewJSRuntime.cs index 6bdfac2617..b56b590b55 100644 --- a/src/Components/WebView/WebView/src/Services/WebViewJSRuntime.cs +++ b/src/Components/WebView/WebView/src/Services/WebViewJSRuntime.cs @@ -30,6 +30,11 @@ internal class WebViewJSRuntime : JSRuntime protected override void BeginInvokeJS(long taskId, string identifier, string argsJson, JSCallResultType resultType, long targetInstanceId) { + if (_ipcSender is null) + { + throw new InvalidOperationException("Cannot invoke JavaScript outside of a WebView context."); + } + _ipcSender.BeginInvokeJS(taskId, identifier, argsJson, resultType, targetInstanceId); } diff --git a/src/Hosting/Abstractions/src/Microsoft.AspNetCore.Hosting.Abstractions.csproj b/src/Hosting/Abstractions/src/Microsoft.AspNetCore.Hosting.Abstractions.csproj index cdcf26e2a5..14efe07f3c 100644 --- a/src/Hosting/Abstractions/src/Microsoft.AspNetCore.Hosting.Abstractions.csproj +++ b/src/Hosting/Abstractions/src/Microsoft.AspNetCore.Hosting.Abstractions.csproj @@ -8,6 +8,7 @@ <PackageTags>aspnetcore;hosting</PackageTags> <IsPackable>false</IsPackable> <Nullable>enable</Nullable> + <Trimmable>true</Trimmable> </PropertyGroup> <ItemGroup> diff --git a/src/Hosting/Server.Abstractions/src/Microsoft.AspNetCore.Hosting.Server.Abstractions.csproj b/src/Hosting/Server.Abstractions/src/Microsoft.AspNetCore.Hosting.Server.Abstractions.csproj index ef3ae05a89..4de09ff8e4 100644 --- a/src/Hosting/Server.Abstractions/src/Microsoft.AspNetCore.Hosting.Server.Abstractions.csproj +++ b/src/Hosting/Server.Abstractions/src/Microsoft.AspNetCore.Hosting.Server.Abstractions.csproj @@ -8,6 +8,7 @@ <PackageTags>aspnetcore;hosting</PackageTags> <IsPackable>false</IsPackable> <Nullable>enable</Nullable> + <Trimmable>true</Trimmable> </PropertyGroup> <ItemGroup> diff --git a/src/Hosting/Server.IntegrationTesting/src/Common/DeploymentResult.cs b/src/Hosting/Server.IntegrationTesting/src/Common/DeploymentResult.cs index dc7101c5f5..588c30e58b 100644 --- a/src/Hosting/Server.IntegrationTesting/src/Common/DeploymentResult.cs +++ b/src/Hosting/Server.IntegrationTesting/src/Common/DeploymentResult.cs @@ -62,5 +62,9 @@ public class DeploymentResult /// <param name="baseHandler"></param> /// <returns></returns> public HttpClient CreateHttpClient(HttpMessageHandler baseHandler) => - new HttpClient(new LoggingHandler(_loggerFactory, baseHandler)) { BaseAddress = new Uri(ApplicationBaseUri) }; + new HttpClient(new LoggingHandler(_loggerFactory, baseHandler)) + { + BaseAddress = new Uri(ApplicationBaseUri), + Timeout = TimeSpan.FromSeconds(200), + }; } diff --git a/src/Hosting/Server.IntegrationTesting/src/Deployers/NginxDeployer.cs b/src/Hosting/Server.IntegrationTesting/src/Deployers/NginxDeployer.cs index a004b07b12..9c09a94445 100644 --- a/src/Hosting/Server.IntegrationTesting/src/Deployers/NginxDeployer.cs +++ b/src/Hosting/Server.IntegrationTesting/src/Deployers/NginxDeployer.cs @@ -77,6 +77,7 @@ public class NginxDeployer : SelfHostDeployer // Target actual address to avoid going through Nginx proxy using (var httpClient = new HttpClient()) { + httpClient.Timeout = TimeSpan.FromSeconds(200); var response = await RetryHelper.RetryRequest(() => { return httpClient.GetAsync(redirectUri); diff --git a/src/Hosting/Server.IntegrationTesting/src/Deployers/RemoteWindowsDeployer/RemoteWindowsDeployer.cs b/src/Hosting/Server.IntegrationTesting/src/Deployers/RemoteWindowsDeployer/RemoteWindowsDeployer.cs index 40b5cd1bcc..b7b8289375 100644 --- a/src/Hosting/Server.IntegrationTesting/src/Deployers/RemoteWindowsDeployer/RemoteWindowsDeployer.cs +++ b/src/Hosting/Server.IntegrationTesting/src/Deployers/RemoteWindowsDeployer/RemoteWindowsDeployer.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; @@ -254,8 +254,8 @@ public class RemoteWindowsDeployer : ApplicationDeployer runScriptsOnRemoteServerProcess.StartAndCaptureOutAndErrToLogger(serverAction, Logger); - // Wait a second for the script to run or fail. The StartServer script will only terminate when the Deployer is disposed, - // so we don't want to wait for it to terminate here because it would deadlock. + // Wait a minute for the script to run or fail. The StartServer script will only terminate when the + // Deployer is disposed, so we don't want to wait for it to terminate here because it would deadlock. await Task.Delay(TimeSpan.FromMinutes(1)); if (runScriptsOnRemoteServerProcess.HasExited && runScriptsOnRemoteServerProcess.ExitCode != 0) diff --git a/src/Hosting/Server.IntegrationTesting/src/Deployers/SelfHostDeployer.cs b/src/Hosting/Server.IntegrationTesting/src/Deployers/SelfHostDeployer.cs index bc299b4363..1abae50c79 100644 --- a/src/Hosting/Server.IntegrationTesting/src/Deployers/SelfHostDeployer.cs +++ b/src/Hosting/Server.IntegrationTesting/src/Deployers/SelfHostDeployer.cs @@ -192,10 +192,10 @@ public class SelfHostDeployer : ApplicationDeployer // Host may not write startup messages, in which case assume it started if (DeploymentParameters.StatusMessagesEnabled) { - // The timeout here is large, because we don't know how long the test could need - // We cover a lot of error cases above, but I want to make sure we eventually give up and don't hang the build - // just in case we missed one -anurse - await started.Task.TimeoutAfter(TimeSpan.FromMinutes(10)); + // The timeout here is large, because we don't know how long the test could need. We cover a lot + // of error cases above, but I want to make sure we eventually give up and don't hang the build + // just in case we missed one. + await started.Task.TimeoutAfter(TimeSpan.FromMinutes(15)); } return (url: actualUrl ?? hintUrl, hostExitToken: hostExitTokenSource.Token); diff --git a/src/Hosting/TestHost/src/TestServer.cs b/src/Hosting/TestHost/src/TestServer.cs index c012b7a004..ed6ab6eb69 100644 --- a/src/Hosting/TestHost/src/TestServer.cs +++ b/src/Hosting/TestHost/src/TestServer.cs @@ -152,7 +152,11 @@ public class TestServer : IServer /// </summary> public HttpClient CreateClient() { - return new HttpClient(CreateHandler()) { BaseAddress = BaseAddress }; + return new HttpClient(CreateHandler()) + { + BaseAddress = BaseAddress, + Timeout = TimeSpan.FromSeconds(200), + }; } /// <summary> diff --git a/src/Http/Http.Extensions/src/HeaderDictionaryTypeExtensions.cs b/src/Http/Http.Extensions/src/HeaderDictionaryTypeExtensions.cs index f7e923a561..fcc8b91c8f 100644 --- a/src/Http/Http.Extensions/src/HeaderDictionaryTypeExtensions.cs +++ b/src/Http/Http.Extensions/src/HeaderDictionaryTypeExtensions.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using System.Reflection; @@ -166,29 +167,29 @@ public static class HeaderDictionaryTypeExtensions } } - private static readonly IDictionary<Type, object> KnownParsers = new Dictionary<Type, object>() - { - { typeof(CacheControlHeaderValue), new Func<string, CacheControlHeaderValue?>(value => { return CacheControlHeaderValue.TryParse(value, out var result) ? result : null; }) }, - { typeof(ContentDispositionHeaderValue), new Func<string, ContentDispositionHeaderValue?>(value => { return ContentDispositionHeaderValue.TryParse(value, out var result) ? result : null; }) }, - { typeof(ContentRangeHeaderValue), new Func<string, ContentRangeHeaderValue?>(value => { return ContentRangeHeaderValue.TryParse(value, out var result) ? result : null; }) }, - { typeof(MediaTypeHeaderValue), new Func<string, MediaTypeHeaderValue?>(value => { return MediaTypeHeaderValue.TryParse(value, out var result) ? result : null; }) }, - { typeof(RangeConditionHeaderValue), new Func<string, RangeConditionHeaderValue?>(value => { return RangeConditionHeaderValue.TryParse(value, out var result) ? result : null; }) }, - { typeof(RangeHeaderValue), new Func<string, RangeHeaderValue?>(value => { return RangeHeaderValue.TryParse(value, out var result) ? result : null; }) }, - { typeof(EntityTagHeaderValue), new Func<string, EntityTagHeaderValue?>(value => { return EntityTagHeaderValue.TryParse(value, out var result) ? result : null; }) }, - { typeof(DateTimeOffset?), new Func<string, DateTimeOffset?>(value => { return HeaderUtilities.TryParseDate(value, out var result) ? result : null; }) }, - { typeof(long?), new Func<string, long?>(value => { return HeaderUtilities.TryParseNonNegativeInt64(value, out var result) ? result : null; }) }, - }; - - private static readonly IDictionary<Type, object> KnownListParsers = new Dictionary<Type, object>() - { - { typeof(MediaTypeHeaderValue), new Func<IList<string>, IList<MediaTypeHeaderValue>>(value => { return MediaTypeHeaderValue.TryParseList(value, out var result) ? result : Array.Empty<MediaTypeHeaderValue>(); }) }, - { typeof(StringWithQualityHeaderValue), new Func<IList<string>, IList<StringWithQualityHeaderValue>>(value => { return StringWithQualityHeaderValue.TryParseList(value, out var result) ? result : Array.Empty<StringWithQualityHeaderValue>(); }) }, - { typeof(CookieHeaderValue), new Func<IList<string>, IList<CookieHeaderValue>>(value => { return CookieHeaderValue.TryParseList(value, out var result) ? result : Array.Empty<CookieHeaderValue>(); }) }, - { typeof(EntityTagHeaderValue), new Func<IList<string>, IList<EntityTagHeaderValue>>(value => { return EntityTagHeaderValue.TryParseList(value, out var result) ? result : Array.Empty<EntityTagHeaderValue>(); }) }, - { typeof(SetCookieHeaderValue), new Func<IList<string>, IList<SetCookieHeaderValue>>(value => { return SetCookieHeaderValue.TryParseList(value, out var result) ? result : Array.Empty<SetCookieHeaderValue>(); }) }, - }; - - internal static T? Get<T>(this IHeaderDictionary headers, string name) + private static readonly Dictionary<Type, object> KnownParsers = new() + { + { typeof(CacheControlHeaderValue), new Func<string, CacheControlHeaderValue?>(value => { return CacheControlHeaderValue.TryParse(value, out var result) ? result : null; }) }, + { typeof(ContentDispositionHeaderValue), new Func<string, ContentDispositionHeaderValue?>(value => { return ContentDispositionHeaderValue.TryParse(value, out var result) ? result : null; }) }, + { typeof(ContentRangeHeaderValue), new Func<string, ContentRangeHeaderValue?>(value => { return ContentRangeHeaderValue.TryParse(value, out var result) ? result : null; }) }, + { typeof(MediaTypeHeaderValue), new Func<string, MediaTypeHeaderValue?>(value => { return MediaTypeHeaderValue.TryParse(value, out var result) ? result : null; }) }, + { typeof(RangeConditionHeaderValue), new Func<string, RangeConditionHeaderValue?>(value => { return RangeConditionHeaderValue.TryParse(value, out var result) ? result : null; }) }, + { typeof(RangeHeaderValue), new Func<string, RangeHeaderValue?>(value => { return RangeHeaderValue.TryParse(value, out var result) ? result : null; }) }, + { typeof(EntityTagHeaderValue), new Func<string, EntityTagHeaderValue?>(value => { return EntityTagHeaderValue.TryParse(value, out var result) ? result : null; }) }, + { typeof(DateTimeOffset?), new Func<string, DateTimeOffset?>(value => { return HeaderUtilities.TryParseDate(value, out var result) ? result : null; }) }, + { typeof(long?), new Func<string, long?>(value => { return HeaderUtilities.TryParseNonNegativeInt64(value, out var result) ? result : null; }) }, + }; + + private static readonly Dictionary<Type, object> KnownListParsers = new() + { + { typeof(MediaTypeHeaderValue), new Func<IList<string>, IList<MediaTypeHeaderValue>>(value => { return MediaTypeHeaderValue.TryParseList(value, out var result) ? result : Array.Empty<MediaTypeHeaderValue>(); }) }, + { typeof(StringWithQualityHeaderValue), new Func<IList<string>, IList<StringWithQualityHeaderValue>>(value => { return StringWithQualityHeaderValue.TryParseList(value, out var result) ? result : Array.Empty<StringWithQualityHeaderValue>(); }) }, + { typeof(CookieHeaderValue), new Func<IList<string>, IList<CookieHeaderValue>>(value => { return CookieHeaderValue.TryParseList(value, out var result) ? result : Array.Empty<CookieHeaderValue>(); }) }, + { typeof(EntityTagHeaderValue), new Func<IList<string>, IList<EntityTagHeaderValue>>(value => { return EntityTagHeaderValue.TryParseList(value, out var result) ? result : Array.Empty<EntityTagHeaderValue>(); }) }, + { typeof(SetCookieHeaderValue), new Func<IList<string>, IList<SetCookieHeaderValue>>(value => { return SetCookieHeaderValue.TryParseList(value, out var result) ? result : Array.Empty<SetCookieHeaderValue>(); }) }, + }; + + internal static T? Get<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T>(this IHeaderDictionary headers, string name) { if (headers == null) { @@ -211,7 +212,7 @@ public static class HeaderDictionaryTypeExtensions return GetViaReflection<T>(value.ToString()); } - internal static IList<T> GetList<T>(this IHeaderDictionary headers, string name) + internal static IList<T> GetList<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T>(this IHeaderDictionary headers, string name) { if (headers == null) { @@ -223,7 +224,7 @@ public static class HeaderDictionaryTypeExtensions return GetList<T>(values); } - internal static IList<T> GetList<T>(this StringValues values) + internal static IList<T> GetList<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T>(this StringValues values) { if (StringValues.IsNullOrEmpty(values)) { @@ -239,31 +240,32 @@ public static class HeaderDictionaryTypeExtensions return GetListViaReflection<T>(values); } - private static T? GetViaReflection<T>(string value) + private static T? GetViaReflection<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T>(string value) { // TODO: Cache the reflected type for later? Only if success? var type = typeof(T); - var method = type.GetMethods(BindingFlags.Public | BindingFlags.Static) - .FirstOrDefault(methodInfo => + MethodInfo? method = null; + foreach (var methodInfo in type.GetMethods(BindingFlags.Public | BindingFlags.Static)) + { + if (string.Equals("TryParse", methodInfo.Name, StringComparison.Ordinal) && + methodInfo.ReturnParameter.ParameterType.Equals(typeof(bool))) { - if (string.Equals("TryParse", methodInfo.Name, StringComparison.Ordinal) - && methodInfo.ReturnParameter.ParameterType.Equals(typeof(bool))) + var methodParams = methodInfo.GetParameters(); + if (methodParams.Length == 2 + && methodParams[0].ParameterType.Equals(typeof(string)) + && methodParams[1].IsOut + && methodParams[1].ParameterType.Equals(type.MakeByRefType())) { - var methodParams = methodInfo.GetParameters(); - return methodParams.Length == 2 - && methodParams[0].ParameterType.Equals(typeof(string)) - && methodParams[1].IsOut - && methodParams[1].ParameterType.Equals(type.MakeByRefType()); + method = methodInfo; + break; } - return false; - }); + } + } - if (method == null) + if (method is null) { - throw new NotSupportedException(string.Format( - CultureInfo.CurrentCulture, - "The given type '{0}' does not have a TryParse method with the required signature 'public static bool TryParse(string, out {0}).", - nameof(T))); + throw new NotSupportedException( + $"The given type '{typeof(T)}' does not have a TryParse method with the required signature 'public static bool TryParse(string, out {typeof(T)})."); } var parameters = new object?[] { value, null }; @@ -275,7 +277,7 @@ public static class HeaderDictionaryTypeExtensions return default(T); } - private static IList<T> GetListViaReflection<T>(StringValues values) + private static IList<T> GetListViaReflection<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T>(StringValues values) { // TODO: Cache the reflected type for later? Only if success? var type = typeof(T); diff --git a/src/Http/Http.Extensions/src/HttpRequestJsonExtensions.cs b/src/Http/Http.Extensions/src/HttpRequestJsonExtensions.cs index 1dfc5e525a..a204e74c04 100644 --- a/src/Http/Http.Extensions/src/HttpRequestJsonExtensions.cs +++ b/src/Http/Http.Extensions/src/HttpRequestJsonExtensions.cs @@ -4,6 +4,8 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; using Microsoft.AspNetCore.Http.Json; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -17,6 +19,9 @@ namespace Microsoft.AspNetCore.Http; /// </summary> public static class HttpRequestJsonExtensions { + private const string RequiresUnreferencedCodeMessage = "JSON serialization and deserialization might require types that cannot be statically analyzed. " + + "Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved."; + /// <summary> /// Read JSON from the request and deserialize to the specified type. /// If the request's content-type is not a known JSON type then an error will be thrown. @@ -25,7 +30,7 @@ public static class HttpRequestJsonExtensions /// <param name="request">The request to read from.</param> /// <param name="cancellationToken">A <see cref="CancellationToken"/> used to cancel the operation.</param> /// <returns>The task object representing the asynchronous operation.</returns> - [SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Required to maintain compatibility")] + [RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)] public static ValueTask<TValue?> ReadFromJsonAsync<TValue>( this HttpRequest request, CancellationToken cancellationToken = default) @@ -42,7 +47,7 @@ public static class HttpRequestJsonExtensions /// <param name="options">The serializer options to use when deserializing the content.</param> /// <param name="cancellationToken">A <see cref="CancellationToken"/> used to cancel the operation.</param> /// <returns>The task object representing the asynchronous operation.</returns> - [SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Required to maintain compatibility")] + [RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)] public static async ValueTask<TValue?> ReadFromJsonAsync<TValue>( this HttpRequest request, JsonSerializerOptions? options, @@ -55,7 +60,7 @@ public static class HttpRequestJsonExtensions if (!request.HasJsonContentType(out var charset)) { - throw CreateContentTypeError(request); + ThrowContentTypeError(request); } options ??= ResolveSerializerOptions(request.HttpContext); @@ -81,10 +86,51 @@ public static class HttpRequestJsonExtensions /// If the request's content-type is not a known JSON type then an error will be thrown. /// </summary> /// <param name="request">The request to read from.</param> + /// <param name="jsonTypeInfo">Metadata about the type to convert.</param> + /// <param name="cancellationToken">A <see cref="CancellationToken"/> used to cancel the operation.</param> + /// <returns>The deserialized value.</returns> +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters + public static async ValueTask<TValue?> ReadFromJsonAsync<TValue>( +#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters + this HttpRequest request, + JsonTypeInfo<TValue> jsonTypeInfo, + CancellationToken cancellationToken = default) + { + if (request == null) + { + throw new ArgumentNullException(nameof(request)); + } + + if (!request.HasJsonContentType(out var charset)) + { + ThrowContentTypeError(request); + } + + var encoding = GetEncodingFromCharset(charset); + var (inputStream, usesTranscodingStream) = GetInputStream(request.HttpContext, encoding); + + try + { + return await JsonSerializer.DeserializeAsync(inputStream, jsonTypeInfo, cancellationToken); + } + finally + { + if (usesTranscodingStream) + { + await inputStream.DisposeAsync(); + } + } + } + + /// <summary> + /// Read JSON from the request and deserialize to the specified type. + /// If the request's content-type is not a known JSON type then an error will be thrown. + /// </summary> + /// <param name="request">The request to read from.</param> /// <param name="type">The type of object to read.</param> /// <param name="cancellationToken">A <see cref="CancellationToken"/> used to cancel the operation.</param> /// <returns>The task object representing the asynchronous operation.</returns> - [SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Required to maintain compatibility")] + [RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)] public static ValueTask<object?> ReadFromJsonAsync( this HttpRequest request, Type type, @@ -102,7 +148,7 @@ public static class HttpRequestJsonExtensions /// <param name="options">The serializer options use when deserializing the content.</param> /// <param name="cancellationToken">A <see cref="CancellationToken"/> used to cancel the operation.</param> /// <returns>The task object representing the asynchronous operation.</returns> - [SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Required to maintain compatibility")] + [RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)] public static async ValueTask<object?> ReadFromJsonAsync( this HttpRequest request, Type type, @@ -120,7 +166,7 @@ public static class HttpRequestJsonExtensions if (!request.HasJsonContentType(out var charset)) { - throw CreateContentTypeError(request); + ThrowContentTypeError(request); } options ??= ResolveSerializerOptions(request.HttpContext); @@ -142,6 +188,59 @@ public static class HttpRequestJsonExtensions } /// <summary> + /// Read JSON from the request and deserialize to the specified type. + /// If the request's content-type is not a known JSON type then an error will be thrown. + /// </summary> + /// <param name="request">The request to read from.</param> + /// <param name="type">The type of object to read.</param> + /// <param name="context">A metadata provider for serializable types.</param> + /// <param name="cancellationToken">A <see cref="CancellationToken"/> used to cancel the operation.</param> + /// <returns>The deserialized value.</returns> +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters + public static async ValueTask<object?> ReadFromJsonAsync( +#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters + this HttpRequest request, + Type type, + JsonSerializerContext context, + CancellationToken cancellationToken = default) + { + if (request is null) + { + throw new ArgumentNullException(nameof(request)); + } + + if (type is null) + { + throw new ArgumentNullException(nameof(type)); + } + + if (context is null) + { + throw new ArgumentNullException(nameof(context)); + } + + if (!request.HasJsonContentType(out var charset)) + { + ThrowContentTypeError(request); + } + + var encoding = GetEncodingFromCharset(charset); + var (inputStream, usesTranscodingStream) = GetInputStream(request.HttpContext, encoding); + + try + { + return await JsonSerializer.DeserializeAsync(inputStream, type, context, cancellationToken); + } + finally + { + if (usesTranscodingStream) + { + await inputStream.DisposeAsync(); + } + } + } + + /// <summary> /// Checks the Content-Type header for JSON types. /// </summary> /// <returns>true if the Content-Type header represents a JSON content type; otherwise, false.</returns> @@ -187,9 +286,10 @@ public static class HttpRequestJsonExtensions return httpContext.RequestServices?.GetService<IOptions<JsonOptions>>()?.Value?.SerializerOptions ?? JsonOptions.DefaultSerializerOptions; } - private static InvalidOperationException CreateContentTypeError(HttpRequest request) + [DoesNotReturn] + private static void ThrowContentTypeError(HttpRequest request) { - return new InvalidOperationException($"Unable to read the request as JSON because the request content type '{request.ContentType}' is not a known JSON content type."); + throw new InvalidOperationException($"Unable to read the request as JSON because the request content type '{request.ContentType}' is not a known JSON content type."); } private static (Stream inputStream, bool usesTranscodingStream) GetInputStream(HttpContext httpContext, Encoding? encoding) diff --git a/src/Http/Http.Extensions/src/HttpResponseJsonExtensions.cs b/src/Http/Http.Extensions/src/HttpResponseJsonExtensions.cs index 93fa3c1f50..cba3ae0acf 100644 --- a/src/Http/Http.Extensions/src/HttpResponseJsonExtensions.cs +++ b/src/Http/Http.Extensions/src/HttpResponseJsonExtensions.cs @@ -3,6 +3,8 @@ using System.Diagnostics.CodeAnalysis; using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; using Microsoft.AspNetCore.Http.Json; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -14,6 +16,9 @@ namespace Microsoft.AspNetCore.Http; /// </summary> public static partial class HttpResponseJsonExtensions { + private const string RequiresUnreferencedCodeMessage = "JSON serialization and deserialization might require types that cannot be statically analyzed. " + + "Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved."; + /// <summary> /// Write the specified value as JSON to the response body. The response content-type will be set to /// <c>application/json; charset=utf-8</c>. @@ -23,13 +28,13 @@ public static partial class HttpResponseJsonExtensions /// <param name="value">The value to write as JSON.</param> /// <param name="cancellationToken">A <see cref="CancellationToken"/> used to cancel the operation.</param> /// <returns>The task object representing the asynchronous operation.</returns> - [SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Required to maintain compatibility")] + [RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)] public static Task WriteAsJsonAsync<TValue>( this HttpResponse response, TValue value, CancellationToken cancellationToken = default) { - return response.WriteAsJsonAsync<TValue>(value, options: null, contentType: null, cancellationToken); + return response.WriteAsJsonAsync(value, options: null, contentType: null, cancellationToken); } /// <summary> @@ -42,14 +47,14 @@ public static partial class HttpResponseJsonExtensions /// <param name="options">The serializer options to use when serializing the value.</param> /// <param name="cancellationToken">A <see cref="CancellationToken"/> used to cancel the operation.</param> /// <returns>The task object representing the asynchronous operation.</returns> - [SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Required to maintain compatibility")] + [RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)] public static Task WriteAsJsonAsync<TValue>( this HttpResponse response, TValue value, JsonSerializerOptions? options, CancellationToken cancellationToken = default) { - return response.WriteAsJsonAsync<TValue>(value, options, contentType: null, cancellationToken); + return response.WriteAsJsonAsync(value, options, contentType: null, cancellationToken); } /// <summary> @@ -63,7 +68,7 @@ public static partial class HttpResponseJsonExtensions /// <param name="contentType">The content-type to set on the response.</param> /// <param name="cancellationToken">A <see cref="CancellationToken"/> used to cancel the operation.</param> /// <returns>The task object representing the asynchronous operation.</returns> - [SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Required to maintain compatibility")] + [RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)] public static Task WriteAsJsonAsync<TValue>( this HttpResponse response, TValue value, @@ -79,15 +84,63 @@ public static partial class HttpResponseJsonExtensions options ??= ResolveSerializerOptions(response.HttpContext); response.ContentType = contentType ?? JsonConstants.JsonContentTypeWithCharset; + // if no user provided token, pass the RequestAborted token and ignore OperationCanceledException if (!cancellationToken.CanBeCanceled) { - return WriteAsJsonAsyncSlow<TValue>(response.Body, value, options, response.HttpContext.RequestAborted); + return WriteAsJsonAsyncSlow(response.Body, value, options, response.HttpContext.RequestAborted); } - return JsonSerializer.SerializeAsync<TValue>(response.Body, value, options, cancellationToken); + return JsonSerializer.SerializeAsync(response.Body, value, options, cancellationToken); } + /// <summary> + /// Write the specified value as JSON to the response body. The response content-type will be set to + /// the specified content-type. + /// </summary> + /// <typeparam name="TValue">The type of object to write.</typeparam> + /// <param name="response">The response to write JSON to.</param> + /// <param name="value">The value to write as JSON.</param> + /// <param name="jsonTypeInfo">Metadata about the type to convert.</param> + /// <param name="contentType">The content-type to set on the response.</param> + /// <param name="cancellationToken">A <see cref="CancellationToken"/> used to cancel the operation.</param> + /// <returns>The task object representing the asynchronous operation.</returns> + [RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)] +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters + public static Task WriteAsJsonAsync<TValue>( +#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters + this HttpResponse response, + TValue value, + JsonTypeInfo<TValue> jsonTypeInfo, + string? contentType = default, + CancellationToken cancellationToken = default) + { + if (response == null) + { + throw new ArgumentNullException(nameof(response)); + } + + response.ContentType = contentType ?? JsonConstants.JsonContentTypeWithCharset; + + // if no user provided token, pass the RequestAborted token and ignore OperationCanceledException + if (!cancellationToken.CanBeCanceled) + { + return WriteAsJsonAsyncSlow(response, value, jsonTypeInfo); + } + + return JsonSerializer.SerializeAsync(response.Body, value, jsonTypeInfo, cancellationToken); + + static async Task WriteAsJsonAsyncSlow(HttpResponse response, TValue value, JsonTypeInfo<TValue> jsonTypeInfo) + { + try + { + await JsonSerializer.SerializeAsync(response.Body, value, jsonTypeInfo, response.HttpContext.RequestAborted); + } + catch (OperationCanceledException) { } + } + } + + [RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)] private static async Task WriteAsJsonAsyncSlow<TValue>( Stream body, TValue value, @@ -96,7 +149,7 @@ public static partial class HttpResponseJsonExtensions { try { - await JsonSerializer.SerializeAsync<TValue>(body, value, options, cancellationToken); + await JsonSerializer.SerializeAsync(body, value, options, cancellationToken); } catch (OperationCanceledException) { } } @@ -110,7 +163,7 @@ public static partial class HttpResponseJsonExtensions /// <param name="type">The type of object to write.</param> /// <param name="cancellationToken">A <see cref="CancellationToken"/> used to cancel the operation.</param> /// <returns>The task object representing the asynchronous operation.</returns> - [SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Required to maintain compatibility")] + [RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)] public static Task WriteAsJsonAsync( this HttpResponse response, object? value, @@ -130,7 +183,7 @@ public static partial class HttpResponseJsonExtensions /// <param name="options">The serializer options to use when serializing the value.</param> /// <param name="cancellationToken">A <see cref="CancellationToken"/> used to cancel the operation.</param> /// <returns>The task object representing the asynchronous operation.</returns> - [SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Required to maintain compatibility")] + [RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)] public static Task WriteAsJsonAsync( this HttpResponse response, object? value, @@ -152,7 +205,7 @@ public static partial class HttpResponseJsonExtensions /// <param name="contentType">The content-type to set on the response.</param> /// <param name="cancellationToken">A <see cref="CancellationToken"/> used to cancel the operation.</param> /// <returns>The task object representing the asynchronous operation.</returns> - [SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Required to maintain compatibility")] + [RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)] public static Task WriteAsJsonAsync( this HttpResponse response, object? value, @@ -183,6 +236,7 @@ public static partial class HttpResponseJsonExtensions return JsonSerializer.SerializeAsync(response.Body, value, type, options, cancellationToken); } + [RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)] private static async Task WriteAsJsonAsyncSlow( Stream body, object? value, @@ -197,6 +251,62 @@ public static partial class HttpResponseJsonExtensions catch (OperationCanceledException) { } } + /// <summary> + /// Write the specified value as JSON to the response body. The response content-type will be set to + /// the specified content-type. + /// </summary> + /// <param name="response">The response to write JSON to.</param> + /// <param name="value">The value to write as JSON.</param> + /// <param name="type">The type of object to write.</param> + /// <param name="context">A metadata provider for serializable types.</param> + /// <param name="contentType">The content-type to set on the response.</param> + /// <param name="cancellationToken">A <see cref="CancellationToken"/> used to cancel the operation.</param> + /// <returns>The task object representing the asynchronous operation.</returns> +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters + public static Task WriteAsJsonAsync( +#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters + this HttpResponse response, + object? value, + Type type, + JsonSerializerContext context, + string? contentType = default, + CancellationToken cancellationToken = default) + { + if (response is null) + { + throw new ArgumentNullException(nameof(response)); + } + + if (type is null) + { + throw new ArgumentNullException(nameof(type)); + } + + if (context is null) + { + throw new ArgumentNullException(nameof(context)); + } + + response.ContentType = contentType ?? JsonConstants.JsonContentTypeWithCharset; + + // if no user provided token, pass the RequestAborted token and ignore OperationCanceledException + if (!cancellationToken.CanBeCanceled) + { + return WriteAsJsonAsyncSlow(); + } + + return JsonSerializer.SerializeAsync(response.Body, value, type, context, cancellationToken); + + async Task WriteAsJsonAsyncSlow() + { + try + { + await JsonSerializer.SerializeAsync(response.Body, value, type, context, cancellationToken); + } + catch (OperationCanceledException) { } + } + } + private static JsonSerializerOptions ResolveSerializerOptions(HttpContext httpContext) { // Attempt to resolve options from DI then fallback to default options diff --git a/src/Http/Http.Extensions/src/Microsoft.AspNetCore.Http.Extensions.csproj b/src/Http/Http.Extensions/src/Microsoft.AspNetCore.Http.Extensions.csproj index 06c4e0bb5f..7ef0c2fb5e 100644 --- a/src/Http/Http.Extensions/src/Microsoft.AspNetCore.Http.Extensions.csproj +++ b/src/Http/Http.Extensions/src/Microsoft.AspNetCore.Http.Extensions.csproj @@ -7,7 +7,7 @@ <GenerateDocumentationFile>true</GenerateDocumentationFile> <PackageTags>aspnetcore</PackageTags> <IsPackable>false</IsPackable> - <Nullable>enable</Nullable> + <Trimmable>true</Trimmable> </PropertyGroup> <ItemGroup> diff --git a/src/Http/Http.Extensions/src/PublicAPI.Unshipped.txt b/src/Http/Http.Extensions/src/PublicAPI.Unshipped.txt index f5825c4e84..ef7c55f866 100644 --- a/src/Http/Http.Extensions/src/PublicAPI.Unshipped.txt +++ b/src/Http/Http.Extensions/src/PublicAPI.Unshipped.txt @@ -2,6 +2,10 @@ Microsoft.AspNetCore.Http.RequestDelegateFactoryOptions.RouteHandlerFilterFactories.get -> System.Collections.Generic.IReadOnlyList<System.Func<Microsoft.AspNetCore.Http.RouteHandlerContext!, Microsoft.AspNetCore.Http.RouteHandlerFilterDelegate!, Microsoft.AspNetCore.Http.RouteHandlerFilterDelegate!>!>? Microsoft.AspNetCore.Http.RequestDelegateFactoryOptions.RouteHandlerFilterFactories.init -> void Microsoft.Extensions.DependencyInjection.RouteHandlerJsonServiceExtensions +static Microsoft.AspNetCore.Http.HttpRequestJsonExtensions.ReadFromJsonAsync(this Microsoft.AspNetCore.Http.HttpRequest! request, System.Type! type, System.Text.Json.Serialization.JsonSerializerContext! context, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask<object?> +static Microsoft.AspNetCore.Http.HttpRequestJsonExtensions.ReadFromJsonAsync<TValue>(this Microsoft.AspNetCore.Http.HttpRequest! request, System.Text.Json.Serialization.Metadata.JsonTypeInfo<TValue>! jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask<TValue?> +static Microsoft.AspNetCore.Http.HttpResponseJsonExtensions.WriteAsJsonAsync(this Microsoft.AspNetCore.Http.HttpResponse! response, object? value, System.Type! type, System.Text.Json.Serialization.JsonSerializerContext! context, string? contentType = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +static Microsoft.AspNetCore.Http.HttpResponseJsonExtensions.WriteAsJsonAsync<TValue>(this Microsoft.AspNetCore.Http.HttpResponse! response, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo<TValue>! jsonTypeInfo, string? contentType = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! static Microsoft.Extensions.DependencyInjection.RouteHandlerJsonServiceExtensions.ConfigureRouteHandlerJsonOptions(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action<Microsoft.AspNetCore.Http.Json.JsonOptions!>! configureOptions) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! Microsoft.AspNetCore.Http.EndpointDescriptionAttribute Microsoft.AspNetCore.Http.EndpointDescriptionAttribute.EndpointDescriptionAttribute(string! description) -> void diff --git a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs index c32a6a7901..7c2fca4c74 100644 --- a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs +++ b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs @@ -2,11 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO.Pipelines; using System.Linq; using System.Linq.Expressions; using System.Reflection; +using System.Runtime.CompilerServices; using System.Security.Claims; using System.Text; using System.Text.Json; @@ -22,6 +24,11 @@ namespace Microsoft.AspNetCore.Http; /// <summary> /// Creates <see cref="RequestDelegate"/> implementations from <see cref="Delegate"/> request handlers. /// </summary> +[UnconditionalSuppressMessage("Trimmer", "IL2026", Justification = "RequestDelegateFactory.Create requires unreferenced code.")] +[UnconditionalSuppressMessage("Trimmer", "IL2060", Justification = "RequestDelegateFactory.Create requires unreferenced code.")] +[UnconditionalSuppressMessage("Trimmer", "IL2072", Justification = "RequestDelegateFactory.Create requires unreferenced code.")] +[UnconditionalSuppressMessage("Trimmer", "IL2075", Justification = "RequestDelegateFactory.Create requires unreferenced code.")] +[UnconditionalSuppressMessage("Trimmer", "IL2077", Justification = "RequestDelegateFactory.Create requires unreferenced code.")] public static partial class RequestDelegateFactory { private static readonly ParameterBindingMethodCache ParameterBindingMethodCache = new(); @@ -96,9 +103,8 @@ public static partial class RequestDelegateFactory /// <param name="handler">A request handler with any number of custom parameters that often produces a response with its return value.</param> /// <param name="options">The <see cref="RequestDelegateFactoryOptions"/> used to configure the behavior of the handler.</param> /// <returns>The <see cref="RequestDelegateResult"/>.</returns> -#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters + [RequiresUnreferencedCode("RequestDelegateFactory performs object creation, serialization and deserialization on the delegates and its parameters. This cannot be statically analyzed.")] public static RequestDelegateResult Create(Delegate handler, RequestDelegateFactoryOptions? options = null) -#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters { if (handler is null) { @@ -125,9 +131,9 @@ public static partial class RequestDelegateFactory /// <param name="targetFactory">Creates the <see langword="this"/> for the non-static method.</param> /// <param name="options">The <see cref="RequestDelegateFactoryOptions"/> used to configure the behavior of the handler.</param> /// <returns>The <see cref="RequestDelegate"/>.</returns> -#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters + + [RequiresUnreferencedCode("RequestDelegateFactory performs object creation, serialization and deserialization on the delegates and its parameters. This cannot be statically analyzed.")] public static RequestDelegateResult Create(MethodInfo methodInfo, Func<HttpContext, object>? targetFactory = null, RequestDelegateFactoryOptions? options = null) -#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters { if (methodInfo is null) { @@ -786,7 +792,7 @@ public static partial class RequestDelegateFactory static async Task<(object? FormValue, bool Successful)> TryReadBodyAsync( HttpContext httpContext, - Type bodyType, + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type bodyType, string parameterTypeName, string parameterName, bool allowEmptyRequestBody, @@ -796,7 +802,7 @@ public static partial class RequestDelegateFactory if (allowEmptyRequestBody && bodyType.IsValueType) { - defaultBodyValue = Activator.CreateInstance(bodyType); + defaultBodyValue = CreateValueType(bodyType); } var bodyValue = defaultBodyValue; @@ -831,6 +837,10 @@ public static partial class RequestDelegateFactory } } + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2067:UnrecognizedReflectionPattern", + Justification = "CreateValueType is only called on a ValueType. You can always create an instance of a ValueType.")] + private static object? CreateValueType(Type t) => RuntimeHelpers.GetUninitializedObject(t); + private static Func<object?, HttpContext, Task> HandleRequestBodyAndCompileRequestDelegateForForm( Expression responseWritingMethodCall, FactoryContext factoryContext) diff --git a/src/Http/Http.Extensions/src/RequestHeaders.cs b/src/Http/Http.Extensions/src/RequestHeaders.cs index 2b86a3e5f3..d6f6cef97a 100644 --- a/src/Http/Http.Extensions/src/RequestHeaders.cs +++ b/src/Http/Http.Extensions/src/RequestHeaders.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.Net.Http.Headers; @@ -357,7 +358,7 @@ public class RequestHeaders /// The given type must have a static TryParse method.</typeparam> /// <param name="name">The name of the header to retrieve.</param> /// <returns>The value of the header.</returns> - public T? Get<T>(string name) + public T? Get<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T>(string name) { return Headers.Get<T>(name); } @@ -370,7 +371,7 @@ public class RequestHeaders /// The given type must have a static TryParseList method.</typeparam> /// <param name="name">The name of the header to retrieve.</param> /// <returns>List of values of the header.</returns> - public IList<T> GetList<T>(string name) + public IList<T> GetList<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T>(string name) { return Headers.GetList<T>(name); } diff --git a/src/Http/Http.Extensions/src/ResponseHeaders.cs b/src/Http/Http.Extensions/src/ResponseHeaders.cs index 66f44542ae..74f13b8d7a 100644 --- a/src/Http/Http.Extensions/src/ResponseHeaders.cs +++ b/src/Http/Http.Extensions/src/ResponseHeaders.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.Net.Http.Headers; @@ -207,7 +208,7 @@ public class ResponseHeaders /// The given type must have a static TryParse method.</typeparam> /// <param name="name">The name of the header to retrieve.</param> /// <returns>The value of the header.</returns> - public T? Get<T>(string name) + public T? Get<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T>(string name) { return Headers.Get<T>(name); } @@ -220,7 +221,7 @@ public class ResponseHeaders /// The given type must have a static TryParseList method.</typeparam> /// <param name="name">The name of the header to retrieve.</param> /// <returns>List of values of the header.</returns> - public IList<T> GetList<T>(string name) + public IList<T> GetList<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T>(string name) { return Headers.GetList<T>(name); } diff --git a/src/Http/Routing.Abstractions/src/Microsoft.AspNetCore.Routing.Abstractions.csproj b/src/Http/Routing.Abstractions/src/Microsoft.AspNetCore.Routing.Abstractions.csproj index db1aa002e8..2eb5ee4cf2 100644 --- a/src/Http/Routing.Abstractions/src/Microsoft.AspNetCore.Routing.Abstractions.csproj +++ b/src/Http/Routing.Abstractions/src/Microsoft.AspNetCore.Routing.Abstractions.csproj @@ -11,6 +11,7 @@ Microsoft.AspNetCore.Routing.RouteData</Description> <PackageTags>aspnetcore;routing</PackageTags> <IsPackable>false</IsPackable> <Nullable>annotations</Nullable> + <Trimmable>true</Trimmable> </PropertyGroup> <ItemGroup> diff --git a/src/Http/Routing/src/Builder/RouteHandlerFilterExtensions.cs b/src/Http/Routing/src/Builder/RouteHandlerFilterExtensions.cs index fae8885ad2..f0032cc2bf 100644 --- a/src/Http/Routing/src/Builder/RouteHandlerFilterExtensions.cs +++ b/src/Http/Routing/src/Builder/RouteHandlerFilterExtensions.cs @@ -32,11 +32,26 @@ public static class RouteHandlerFilterExtensions /// <returns>A <see cref="RouteHandlerBuilder"/> that can be used to further customize the route handler.</returns> public static RouteHandlerBuilder AddFilter<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TFilterType>(this RouteHandlerBuilder builder) where TFilterType : IRouteHandlerFilter { - var filterFactory = ActivatorUtilities.CreateFactory(typeof(TFilterType), Type.EmptyTypes); - builder.RouteHandlerFilterFactories.Add((routeHandlerContext, next) => (context) => + // We call `CreateFactory` twice here since the `CreateFactory` API does not support optional arguments. + // See https://github.com/dotnet/runtime/issues/67309 for more info. + ObjectFactory filterFactory; + try { - var filter = (IRouteHandlerFilter)filterFactory.Invoke(context.HttpContext.RequestServices, Array.Empty<object>()); - return filter.InvokeAsync(context, next); + filterFactory = ActivatorUtilities.CreateFactory(typeof(TFilterType), new[] { typeof(RouteHandlerContext) }); + } + catch (InvalidOperationException) + { + filterFactory = ActivatorUtilities.CreateFactory(typeof(TFilterType), Type.EmptyTypes); + } + + builder.RouteHandlerFilterFactories.Add((routeHandlerContext, next) => + { + var invokeArguments = new[] { routeHandlerContext }; + return (context) => + { + var filter = (IRouteHandlerFilter)filterFactory.Invoke(context.HttpContext.RequestServices, invokeArguments); + return filter.InvokeAsync(context, next); + }; }); return builder; } diff --git a/src/Http/Routing/test/UnitTests/Builder/RouteHandlerEndpointRouteBuilderExtensionsTest.cs b/src/Http/Routing/test/UnitTests/Builder/RouteHandlerEndpointRouteBuilderExtensionsTest.cs index b9d4e58607..f5685ecbb1 100644 --- a/src/Http/Routing/test/UnitTests/Builder/RouteHandlerEndpointRouteBuilderExtensionsTest.cs +++ b/src/Http/Routing/test/UnitTests/Builder/RouteHandlerEndpointRouteBuilderExtensionsTest.cs @@ -850,7 +850,7 @@ public class RouteHandlerEndpointRouteBuilderExtensionsTest : LoggedTest } public static object[][] AddFiltersByClassData = -{ + { new object[] { (Action<RouteHandlerBuilder>)((RouteHandlerBuilder builder) => builder.AddFilter(new IncrementArgFilter())) }, new object[] { (Action<RouteHandlerBuilder>)((RouteHandlerBuilder builder) => builder.AddFilter<IncrementArgFilter>()) } }; @@ -948,7 +948,7 @@ public class RouteHandlerEndpointRouteBuilderExtensionsTest : LoggedTest { var builder = new DefaultEndpointRouteBuilder(new ApplicationBuilder(new ServiceCollection().BuildServiceProvider())); - string? PrintLogger(HttpContext context) => $"loggerErrorIsEnabled: {context.Items["loggerErrorIsEnabled"]}"; + string? PrintLogger(HttpContext context) => $"loggerErrorIsEnabled: {context.Items["loggerErrorIsEnabled"]}, parentName: {context.Items["parentName"]}"; var routeHandlerBuilder = builder.Map("/", PrintLogger); routeHandlerBuilder.AddFilter<ServiceAccessingRouteHandlerFilter>(); @@ -969,21 +969,24 @@ public class RouteHandlerEndpointRouteBuilderExtensionsTest : LoggedTest httpResponse.Body.Seek(0, SeekOrigin.Begin); var streamReader = new StreamReader(httpResponse.Body); var body = streamReader.ReadToEndAsync().Result; - Assert.Equal("loggerErrorIsEnabled: True", body); + Assert.Equal("loggerErrorIsEnabled: True, parentName: RouteHandlerEndpointRouteBuilderExtensionsTest", body); } class ServiceAccessingRouteHandlerFilter : IRouteHandlerFilter { private ILogger _logger; + private RouteHandlerContext _routeHandlerContext; - public ServiceAccessingRouteHandlerFilter(ILoggerFactory loggerFactory) + public ServiceAccessingRouteHandlerFilter(ILoggerFactory loggerFactory, RouteHandlerContext routeHandlerContext) { _logger = loggerFactory.CreateLogger<ServiceAccessingRouteHandlerFilter>(); + _routeHandlerContext = routeHandlerContext; } public async ValueTask<object?> InvokeAsync(RouteHandlerInvocationContext context, RouteHandlerFilterDelegate next) { context.HttpContext.Items["loggerErrorIsEnabled"] = _logger.IsEnabled(LogLevel.Error); + context.HttpContext.Items["parentName"] = _routeHandlerContext.MethodInfo.DeclaringType?.Name; return await next(context); } } diff --git a/src/Identity/UI/src/Microsoft.AspNetCore.Identity.UI.csproj b/src/Identity/UI/src/Microsoft.AspNetCore.Identity.UI.csproj index 47f13da796..e5c0ef0f56 100644 --- a/src/Identity/UI/src/Microsoft.AspNetCore.Identity.UI.csproj +++ b/src/Identity/UI/src/Microsoft.AspNetCore.Identity.UI.csproj @@ -22,6 +22,7 @@ </PropertyGroup> <ItemGroup> + <Content Remove="@(Content)" /> <None Include="build\*" Pack="true" PackagePath="build\" /> <None Include="buildMultiTargeting\*" Pack="true" PackagePath="buildMultiTargeting\" /> <None Include="buildTransitive\*" Pack="true" PackagePath="buildTransitive\" /> diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/include.wxi b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/include.wxi index c4992860a3..98ee8aeb34 100644 --- a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/include.wxi +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/include.wxi @@ -2,6 +2,12 @@ <Include> <?define DiscoverabilityKeyRoot = "SOFTWARE\Microsoft\IIS Extensions"?> + + <!-- NativeMachine values match the expected values for image file machine constants + https://docs.microsoft.com/en-us/windows/win32/sysinfo/image-file-machine-constants --> + <?define NativeMachine_x86=332?> + <?define NativeMachine_x64=34404?> + <?define NativeMachine_arm64=43620?> <?if $(var.Platform) = "x64"?> <?define IsWin64 = yes ?> diff --git a/src/Installers/Windows/WindowsHostingBundle/ANCM.wxs b/src/Installers/Windows/WindowsHostingBundle/ANCM.wxs index b9ca54eb8f..4deeaed434 100644 --- a/src/Installers/Windows/WindowsHostingBundle/ANCM.wxs +++ b/src/Installers/Windows/WindowsHostingBundle/ANCM.wxs @@ -1,4 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> +<?include ..\AspNetCoreModule-Setup\IIS-Setup\include.wxi ?> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension" xmlns:bal="http://schemas.microsoft.com/wix/BalExtension"> <Fragment> <PackageGroup Id="PG_ANCM"> @@ -10,7 +11,7 @@ Compressed="yes" Vital="yes" Visible="no" - InstallCondition="NOT VersionNT64 AND (VersionNT >= v6.1) AND (IISCoreWebEngineInstalled_x86=1) AND (IISW3SVCInstalled_x86=1) AND (NOT OPT_NO_ANCM OR OPT_NO_ANCM="0")"> + InstallCondition="(NativeMachine="$(var.NativeMachine_x86)") AND (IISCoreWebEngineInstalled_x86=1) AND (IISW3SVCInstalled_x86=1) AND (NOT OPT_NO_ANCM OR OPT_NO_ANCM="0")"> <MsiProperty Name="OPT_NO_SHARED_CONFIG_CHECK" Value="[OPT_NO_SHARED_CONFIG_CHECK]" /> </MsiPackage> @@ -20,11 +21,22 @@ Compressed="yes" Vital="yes" Visible="no" - InstallCondition="VersionNT64 AND (VersionNT64 >= v6.1) AND (IISCoreWebEngineInstalled_x64=1) AND (IISW3SVCInstalled_x64=1) AND (NOT OPT_NO_ANCM OR OPT_NO_ANCM="0")"> + InstallCondition="(NativeMachine="$(var.NativeMachine_x64)") AND (IISCoreWebEngineInstalled_x64=1) AND (IISW3SVCInstalled_x64=1) AND (NOT OPT_NO_ANCM OR OPT_NO_ANCM="0")"> <MsiProperty Name="OPT_NO_SHARED_CONFIG_CHECK" Value="[OPT_NO_SHARED_CONFIG_CHECK]" /> </MsiPackage> + + <!-- OPT_NO_SHARED_CONFIG_CHECK could be unset at this point, which we explicitly treat as 'false' --> + <MsiPackage Id="AspNetCoreModuleV2_arm64" SourceFile="$(var.AspNetCoreModuleV2_arm64.TargetPath)" + Name="$(var.AspNetCoreModuleV2_arm64.TargetFileName)" + Compressed="yes" + Vital="yes" + Visible="no" + InstallCondition="(NativeMachine="$(var.NativeMachine_arm64)") AND (IISCoreWebEngineInstalled_x64=1) AND (IISW3SVCInstalled_x64=1) AND (NOT OPT_NO_ANCM OR OPT_NO_ANCM="0")"> + <MsiProperty Name="OPT_NO_SHARED_CONFIG_CHECK" Value="[OPT_NO_SHARED_CONFIG_CHECK]" /> + </MsiPackage> + </PackageGroup> - + <util:RegistrySearch Id="IISCoreWebEngineInstalledSearch_x86" Variable="IISCoreWebEngineInstalled_x86" Root="HKLM" diff --git a/src/Installers/Windows/WindowsHostingBundle/DotNetCore.wxs b/src/Installers/Windows/WindowsHostingBundle/DotNetCore.wxs index 25e549b0de..73a80bdbb3 100644 --- a/src/Installers/Windows/WindowsHostingBundle/DotNetCore.wxs +++ b/src/Installers/Windows/WindowsHostingBundle/DotNetCore.wxs @@ -1,15 +1,28 @@ <?xml version="1.0" encoding="UTF-8"?> +<?include ..\AspNetCoreModule-Setup\IIS-Setup\include.wxi ?> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"> <Fragment> <PackageGroup Id="PG_DOTNET_REDIST_LTS_BUNDLE"> <RollbackBoundary Id="RB_DOTNET_REDIST_LTS_BUNDLE" /> <!-- OPT_NO_RUNTIME could be unset at this point, which we explicitly treat as 'false' --> + <ExePackage Id="DotNetRedistLts_arm64" SourceFile="$(var.DepsPath)\$(var.DotNetRedistLtsInstallerarm64)" + Name="$(var.DotNetRedistLtsInstallerarm64)" + Compressed="yes" + Vital="yes" + InstallCondition="(NativeMachine="$(var.NativeMachine_arm64)") AND (NOT OPT_NO_RUNTIME OR OPT_NO_RUNTIME="0")" + InstallCommand="/quiet /norestart" + RepairCommand="/quiet /repair" + Permanent="yes" + DetectCondition="DotNetRedistLtsProductVersion_arm64 = v$(var.DotNetRedistLtsInstallerProductVersionarm64)"> + </ExePackage> + + <!-- OPT_NO_RUNTIME could be unset at this point, which we explicitly treat as 'false' --> <ExePackage Id="DotNetRedistLts_x64" SourceFile="$(var.DepsPath)\$(var.DotNetRedistLtsInstallerx64)" Name="$(var.DotNetRedistLtsInstallerx64)" Compressed="yes" Vital="yes" - InstallCondition="VersionNT64 AND (NOT OPT_NO_RUNTIME OR OPT_NO_RUNTIME="0")" + InstallCondition="(NativeMachine="$(var.NativeMachine_x64)") AND (NOT OPT_NO_RUNTIME OR OPT_NO_RUNTIME="0")" InstallCommand="/quiet /norestart" RepairCommand="/quiet /repair" Permanent="yes" @@ -32,15 +45,22 @@ <Fragment> <util:ProductSearch Id="DotNetRedistLtsProductSearch_x86" - Condition="NOT VersionNT64" + Condition="(NativeMachine="$(var.NativeMachine_x86)")" ProductCode="$(var.DotNetRedistLtsInstallerProductCodex86)" Result="version" Variable="DotNetRedistLtsProductVersion_x86" /> <util:ProductSearch Id="DotNetRedistLtsProductSearch_x64" - Condition="VersionNT64" + Condition="(NativeMachine="$(var.NativeMachine_x64)")" ProductCode="$(var.DotNetRedistLtsInstallerProductCodex64)" Result="version" Variable="DotNetRedistLtsProductVersion_x64" /> + + <util:ProductSearch Id="DotNetRedistLtsProductSearch_arm64" + Condition="(NativeMachine="$(var.NativeMachine_arm64)")" + ProductCode="$(var.DotNetRedistLtsInstallerProductCodearm64)" + Result="version" + Variable="DotNetRedistLtsProductVersion_arm64" /> + </Fragment> </Wix> diff --git a/src/Installers/Windows/WindowsHostingBundle/Product.targets b/src/Installers/Windows/WindowsHostingBundle/Product.targets index e446b9f5df..dab4141773 100644 --- a/src/Installers/Windows/WindowsHostingBundle/Product.targets +++ b/src/Installers/Windows/WindowsHostingBundle/Product.targets @@ -7,7 +7,7 @@ </PropertyGroup> <ItemGroup> - <Platforms Include="x64;x86" /> + <Platforms Include="x64;x86;arm64" /> <RuntimeInstallers Include="$(DepsPath)dotnet-runtime-$(MicrosoftNETCoreAppRuntimeVersion)-win-x64.exe"> <TargetPlatform>x64</TargetPlatform> <BundleNameProperty>DotNetRedistLtsInstallerx64</BundleNameProperty> @@ -18,6 +18,11 @@ <BundleNameProperty>DotNetRedistLtsInstallerx86</BundleNameProperty> <Version>$(MicrosoftNETCoreAppRuntimeVersion)</Version> </RuntimeInstallers> + <RuntimeInstallers Include="$(DepsPath)dotnet-runtime-$(MicrosoftNETCoreAppRuntimeVersion)-win-arm64.exe"> + <TargetPlatform>arm64</TargetPlatform> + <BundleNameProperty>DotNetRedistLtsInstallerarm64</BundleNameProperty> + <Version>$(MicrosoftNETCoreAppRuntimeVersion)</Version> + </RuntimeInstallers> </ItemGroup> <Target Name="FetchDependencies" BeforeTargets="Restore;CollectPackageReferences"> @@ -36,6 +41,9 @@ <RemoteAsset Include="Runtime/$(MicrosoftNETCoreBrowserDebugHostTransportVersion)/dotnet-runtime-$(MicrosoftNETCoreAppRuntimeVersion)-win-x86.exe"> <TargetFileName>dotnet-runtime-$(MicrosoftNETCoreAppRuntimeVersion)-win-x86.exe</TargetFileName> </RemoteAsset> + <RemoteAsset Include="Runtime/$(MicrosoftNETCoreBrowserDebugHostTransportVersion)/dotnet-runtime-$(MicrosoftNETCoreAppRuntimeVersion)-win-arm64.exe"> + <TargetFileName>dotnet-runtime-$(MicrosoftNETCoreAppRuntimeVersion)-win-arm64.exe</TargetFileName> + </RemoteAsset> </ItemGroup> <MakeDir Directories="$(DepsPath)" /> @@ -86,6 +94,10 @@ <DefineConstants>$(DefineConstants);DotNetRedistLtsInstallerProductVersionx86=$(DotNetRedistLtsInstallerProductVersionx86)</DefineConstants> <DefineConstants>$(DefineConstants);DotNetRedistLtsInstallerProductCodex86=$(DotNetRedistLtsInstallerProductCodex86)</DefineConstants> <DefineConstants>$(DefineConstants);DotNetRedistLtsInstallerUpgradeCodex86=$(DotNetRedistLtsInstallerUpgradeCodex86)</DefineConstants> + <DefineConstants>$(DefineConstants);DotNetRedistLtsInstallerarm64=$(DotNetRedistLtsInstallerarm64)</DefineConstants> + <DefineConstants>$(DefineConstants);DotNetRedistLtsInstallerProductVersionarm64=$(DotNetRedistLtsInstallerProductVersionarm64)</DefineConstants> + <DefineConstants>$(DefineConstants);DotNetRedistLtsInstallerProductCodearm64=$(DotNetRedistLtsInstallerProductCodearm64)</DefineConstants> + <DefineConstants>$(DefineConstants);DotNetRedistLtsInstallerUpgradeCodearm64=$(DotNetRedistLtsInstallerUpgradeCodearm64)</DefineConstants> </PropertyGroup> </Target> </Project> diff --git a/src/Installers/Windows/WindowsHostingBundle/SharedFramework.wxs b/src/Installers/Windows/WindowsHostingBundle/SharedFramework.wxs index c75b5eb362..79671beb84 100644 --- a/src/Installers/Windows/WindowsHostingBundle/SharedFramework.wxs +++ b/src/Installers/Windows/WindowsHostingBundle/SharedFramework.wxs @@ -1,15 +1,28 @@ <?xml version="1.0" encoding="UTF-8"?> +<?include ..\AspNetCoreModule-Setup\IIS-Setup\include.wxi ?> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"> <Fragment> <PackageGroup Id="PG_SHAREDFX_REDIST_BUNDLE"> <RollbackBoundary Id="RB_SHAREDFX_REDIST_BUNDLE" /> <!-- OPT_NO_SHAREDFX could be unset at this point, which we explicitly treat as 'false' --> + <ExePackage Id="SharedFxRedist_arm64" SourceFile="$(var.InstallersOutputPath)\$(var.SharedFxRedistInstallerarm64)" + Name="$(var.SharedFxRedistInstallerarm64)" + Compressed="yes" + Vital="yes" + InstallCondition="(NativeMachine="$(var.NativeMachine_arm64)") AND (NOT OPT_NO_SHAREDFX OR OPT_NO_SHAREDFX="0")" + InstallCommand="/quiet /norestart" + RepairCommand="/quiet /repair" + Permanent="yes" + DetectCondition="SharedFxRedistProductVersion_arm64 = v$(var.SharedFxInstallerProductVersionarm64)"> + </ExePackage> + + <!-- OPT_NO_SHAREDFX could be unset at this point, which we explicitly treat as 'false' --> <ExePackage Id="SharedFxRedist_x64" SourceFile="$(var.InstallersOutputPath)\$(var.SharedFxRedistInstallerx64)" Name="$(var.SharedFxRedistInstallerx64)" Compressed="yes" Vital="yes" - InstallCondition="VersionNT64 AND (NOT OPT_NO_SHAREDFX OR OPT_NO_SHAREDFX="0")" + InstallCondition="(NativeMachine="$(var.NativeMachine_x64)") AND (NOT OPT_NO_SHAREDFX OR OPT_NO_SHAREDFX="0")" InstallCommand="/quiet /norestart" RepairCommand="/quiet /repair" Permanent="yes" @@ -27,20 +40,27 @@ Permanent="yes" DetectCondition="SharedFxRedistProductVersion_x86 = v$(var.SharedFxInstallerProductVersionx86)"> </ExePackage> + </PackageGroup> </Fragment> <Fragment> <util:ProductSearch Id="SharedFxRedistProductSearch_x86" - Condition="NOT VersionNT64" + Condition="(NativeMachine="$(var.NativeMachine_x86)")" ProductCode="$(var.SharedFxInstallerProductCodex86)" Result="version" Variable="SharedFxRedistProductVersion_x86" /> <util:ProductSearch Id="SharedFxRedistProductSearch_x64" - Condition="VersionNT64" + Condition="(NativeMachine="$(var.NativeMachine_x64)")" ProductCode="$(var.SharedFxInstallerProductCodex64)" Result="version" Variable="SharedFxRedistProductVersion_x64" /> + + <util:ProductSearch Id="SharedFxRedistProductSearch_arm64" + Condition="(NativeMachine="$(var.NativeMachine_arm64)")" + ProductCode="$(var.SharedFxInstallerProductCodearm64)" + Result="version" + Variable="SharedFxRedistProductVersion_arm64" /> </Fragment> </Wix> diff --git a/src/Installers/Windows/WindowsHostingBundle/WindowsHostingBundle.wixproj b/src/Installers/Windows/WindowsHostingBundle/WindowsHostingBundle.wixproj index 2884081b78..e7c9da7d2b 100644 --- a/src/Installers/Windows/WindowsHostingBundle/WindowsHostingBundle.wixproj +++ b/src/Installers/Windows/WindowsHostingBundle/WindowsHostingBundle.wixproj @@ -54,6 +54,13 @@ <Private>True</Private> <DoNotHarvest>true</DoNotHarvest> </ProjectReference> + <ProjectReference Include="..\AspNetCoreModule-Setup\ANCMV2\ANCMV2.wixproj"> + <SetPlatform>Platform=arm64</SetPlatform> + <Name>AspNetCoreModuleV2_arm64</Name> + <Project>f9bacb48-3bd7-4ec2-ae31-664e8703ec12</Project> + <Private>True</Private> + <DoNotHarvest>true</DoNotHarvest> + </ProjectReference> <ProjectReference Include="..\SharedFrameworkBundle\SharedFrameworkBundle.wixproj" Private="false" ReferenceOutputAssembly="false" @@ -107,6 +114,11 @@ <BundleNameProperty>SharedFxRedistInstallerx86</BundleNameProperty> <Version>$(SharedFxPackageVersion)</Version> </SharedFxInstallers> + <SharedFxInstallers Include="$(InstallersOutputPath)$(RuntimeInstallerBaseName)-$(SharedFxPackageVersion)-win-arm64.exe"> + <TargetPlatform>arm64</TargetPlatform> + <BundleNameProperty>SharedFxRedistInstallerarm64</BundleNameProperty> + <Version>$(SharedFxPackageVersion)</Version> + </SharedFxInstallers> </ItemGroup> <PropertyGroup> @@ -137,6 +149,10 @@ <ProductVersionProperty>SharedFxInstallerProductVersionx86</ProductVersionProperty> <ProductCodeProperty>SharedFxInstallerProductCodex86</ProductCodeProperty> </SharedFxPayload> + <SharedFxPayload Include="$(InstallersOutputPath)$(RuntimeInstallerBaseName)-$(SharedFxMsiVersion)-win-arm64.msi"> + <ProductVersionProperty>SharedFxInstallerProductVersionarm64</ProductVersionProperty> + <ProductCodeProperty>SharedFxInstallerProductCodearm64</ProductCodeProperty> + </SharedFxPayload> </ItemGroup> <!-- Read MSI properties --> @@ -154,6 +170,9 @@ <DefineConstants>$(DefineConstants);SharedFxRedistInstallerx86=$(SharedFxRedistInstallerx86)</DefineConstants> <DefineConstants>$(DefineConstants);SharedFxInstallerProductVersionx86=$(SharedFxInstallerProductVersionx86)</DefineConstants> <DefineConstants>$(DefineConstants);SharedFxInstallerProductCodex86=$(SharedFxInstallerProductCodex86)</DefineConstants> + <DefineConstants>$(DefineConstants);SharedFxRedistInstallerarm64=$(SharedFxRedistInstallerarm64)</DefineConstants> + <DefineConstants>$(DefineConstants);SharedFxInstallerProductVersionarm64=$(SharedFxInstallerProductVersionarm64)</DefineConstants> + <DefineConstants>$(DefineConstants);SharedFxInstallerProductCodearm64=$(SharedFxInstallerProductCodearm64)</DefineConstants> </PropertyGroup> </Target> </Project> diff --git a/src/JSInterop/Microsoft.JSInterop/src/Infrastructure/DotNetDispatcher.cs b/src/JSInterop/Microsoft.JSInterop/src/Infrastructure/DotNetDispatcher.cs index 2f591b67f8..46a77c390e 100644 --- a/src/JSInterop/Microsoft.JSInterop/src/Infrastructure/DotNetDispatcher.cs +++ b/src/JSInterop/Microsoft.JSInterop/src/Infrastructure/DotNetDispatcher.cs @@ -10,6 +10,7 @@ using System.Reflection.Metadata; using System.Runtime.ExceptionServices; using System.Text; using System.Text.Json; +using Microsoft.AspNetCore.Internal; [assembly: MetadataUpdateHandler(typeof(Microsoft.JSInterop.Infrastructure.DotNetDispatcher))] @@ -22,12 +23,17 @@ namespace Microsoft.JSInterop.Infrastructure; public static class DotNetDispatcher { private const string DisposeDotNetObjectReferenceMethodName = "__Dispose"; + internal static readonly JsonEncodedText DotNetObjectRefKey = JsonEncodedText.Encode("__dotNetObject"); private static readonly ConcurrentDictionary<AssemblyKey, IReadOnlyDictionary<string, (MethodInfo, Type[])>> _cachedMethodsByAssembly = new(); private static readonly ConcurrentDictionary<Type, IReadOnlyDictionary<string, (MethodInfo, Type[])>> _cachedMethodsByType = new(); + private static readonly ConcurrentDictionary<Type, Func<object, Task>> _cachedConvertToTaskByType = new(); + + private static readonly MethodInfo _taskConverterMethodInfo = typeof(DotNetDispatcher).GetMethod(nameof(CreateValueTaskConverter), BindingFlags.NonPublic | BindingFlags.Static)!; + /// <summary> /// Receives a call from JS to .NET, locating and invoking the specified method. /// </summary> @@ -108,6 +114,19 @@ public static class DotNetDispatcher // Returned a task - we need to continue that task and then report an exception // or return the value. task.ContinueWith(t => EndInvokeDotNetAfterTask(t, jsRuntime, invocationInfo), TaskScheduler.Current); + + } + else if(syncResult is ValueTask valueTaskResult) + { + valueTaskResult.AsTask().ContinueWith(t => EndInvokeDotNetAfterTask(t, jsRuntime, invocationInfo), TaskScheduler.Current); + } + else if (syncResult?.GetType() is { IsGenericType: true } syncResultType + && syncResultType.GetGenericTypeDefinition() == typeof(ValueTask<>)) + { + // It's a ValueTask<T>. We'll coerce it to a Task so that we can attach a continuation. + var innerTask = GetTaskByType(syncResultType.GenericTypeArguments[0], syncResult); + + innerTask!.ContinueWith(t => EndInvokeDotNetAfterTask(t, jsRuntime, invocationInfo), TaskScheduler.Current); } else { @@ -348,6 +367,20 @@ public static class DotNetDispatcher } } + [UnconditionalSuppressMessage( + "ReflectionAnalysis", + "IL2060:MakeGenericMethod", + Justification = "https://github.com/mono/linker/issues/1727")] + private static Task GetTaskByType(Type type, object obj) + { + var converterDelegate = _cachedConvertToTaskByType.GetOrAdd(type, (Type t, MethodInfo taskConverterMethodInfo) => + taskConverterMethodInfo.MakeGenericMethod(t).CreateDelegate<Func<object, Task>>(), _taskConverterMethodInfo); + + return converterDelegate.Invoke(obj); + } + + private static Task CreateValueTaskConverter<[DynamicallyAccessedMembers(LinkerFlags.JsonSerialized)] T>(object result) => ((ValueTask<T>)result).AsTask(); + private static (MethodInfo methodInfo, Type[] parameterTypes) GetCachedMethodInfo(IDotNetObjectReference objectReference, string methodIdentifier) { var type = objectReference.Value.GetType(); @@ -470,6 +503,7 @@ public static class DotNetDispatcher { _cachedMethodsByAssembly.Clear(); _cachedMethodsByType.Clear(); + _cachedConvertToTaskByType.Clear(); } private readonly struct AssemblyKey : IEquatable<AssemblyKey> diff --git a/src/JSInterop/Microsoft.JSInterop/src/Microsoft.JSInterop.WarningSuppressions.xml b/src/JSInterop/Microsoft.JSInterop/src/Microsoft.JSInterop.WarningSuppressions.xml index a1c7043de5..6306606df5 100644 --- a/src/JSInterop/Microsoft.JSInterop/src/Microsoft.JSInterop.WarningSuppressions.xml +++ b/src/JSInterop/Microsoft.JSInterop/src/Microsoft.JSInterop.WarningSuppressions.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8"?> <linker> <assembly fullname="Microsoft.JSInterop, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60"> <attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute"> @@ -39,6 +39,12 @@ </attribute> <attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute"> <argument>ILLink</argument> + <argument>IL2060</argument> + <property name="Scope">member</property> + <property name="Target">M:Microsoft.JSInterop.Infrastructure.DotNetDispatcher.<>c.<GetTaskByType>b__14_0(System.Type,System.Reflection.MethodInfo)</property> + </attribute> + <attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute"> + <argument>ILLink</argument> <argument>IL2065</argument> <property name="Scope">member</property> <property name="Target">M:Microsoft.JSInterop.Infrastructure.DotNetDispatcher.ScanAssemblyForCallableMethods(Microsoft.JSInterop.Infrastructure.DotNetDispatcher.AssemblyKey)</property> @@ -62,4 +68,4 @@ <property name="Target">M:Microsoft.JSInterop.JSRuntimeExtensions.<InvokeAsync>d__4`1.MoveNext</property> </attribute> </assembly> -</linker>
\ No newline at end of file +</linker> diff --git a/src/JSInterop/Microsoft.JSInterop/test/Infrastructure/DotNetDispatcherTest.cs b/src/JSInterop/Microsoft.JSInterop/test/Infrastructure/DotNetDispatcherTest.cs index 53ef5fd389..6dfd73d51c 100644 --- a/src/JSInterop/Microsoft.JSInterop/test/Infrastructure/DotNetDispatcherTest.cs +++ b/src/JSInterop/Microsoft.JSInterop/test/Infrastructure/DotNetDispatcherTest.cs @@ -609,6 +609,60 @@ public class DotNetDispatcherTest Assert.Equal(2468, resultDto2.IntVal); } + [Fact] + public async Task CanInvokeAsyncMethodReturningValueTask() + { + // Arrange: Track some instance plus another object we'll pass as a param + var jsRuntime = new TestJSRuntime(); + var targetInstance = new SomePublicType(); + var arg2 = new TestDTO { IntVal = 1234, StringVal = "My string" }; + var arg1Ref = DotNetObjectReference.Create(targetInstance); + var arg2Ref = DotNetObjectReference.Create(arg2); + jsRuntime.Invoke<object>("unimportant", arg1Ref, arg2Ref); + + // Arrange: all args + var argsJson = JsonSerializer.Serialize(new object[] + { + new TestDTO { IntVal = 1000, StringVal = "String via JSON" }, + arg2Ref, + }, jsRuntime.JsonSerializerOptions); + + // Act + var callId = "123"; + var resultTask = jsRuntime.NextInvocationTask; + DotNetDispatcher.BeginInvokeDotNet(jsRuntime, new DotNetInvocationInfo(null, + nameof(SomePublicType.InvokableAsyncMethodReturningValueTask), 1, callId), argsJson); + await resultTask; + + // Assert: Correct completion information + Assert.Equal(callId, jsRuntime.LastCompletionCallId); + Assert.True(jsRuntime.LastCompletionResult.Success); + } + + [Fact] + public async Task CanInvokeAsyncMethodReturningNonGenericValueTask() + { + // Arrange: Track some instance plus another object we'll pass as a param + var jsRuntime = new TestJSRuntime(); + var targetInstance = new SomePublicType(); + var arg1Ref = DotNetObjectReference.Create(targetInstance); + jsRuntime.Invoke<object>("unimportant", arg1Ref); + + // Arrange: all args + var argsJson = JsonSerializer.Serialize(new object[] { }, jsRuntime.JsonSerializerOptions); + + // Act + var callId = "123"; + var resultTask = jsRuntime.NextInvocationTask; + DotNetDispatcher.BeginInvokeDotNet(jsRuntime, new DotNetInvocationInfo(null, + nameof(SomePublicType.InvokableAsyncMethodReturningValueTaskNonGeneric), 1, callId), argsJson); + await resultTask; + + // Assert: Correct completion information + Assert.Equal(callId, jsRuntime.LastCompletionCallId); + Assert.True(jsRuntime.LastCompletionResult.Success); + } + [Fact] public async Task CanInvokeSyncThrowingMethod() { @@ -878,6 +932,32 @@ public class DotNetDispatcherTest }; } + [JSInvokable] + public async ValueTask<InvokableAsyncMethodResult> InvokableAsyncMethodReturningValueTask(TestDTO dtoViaJson, DotNetObjectReference<TestDTO> dtoByRefWrapper) + { + var dtoByRef = dtoByRefWrapper.Value; + return await new ValueTask<InvokableAsyncMethodResult>( new InvokableAsyncMethodResult() + { + SomeDTO = new TestDTO // Return via JSON + { + StringVal = dtoViaJson.StringVal.ToUpperInvariant(), + IntVal = dtoViaJson.IntVal * 2, + }, + SomeDTORef = DotNetObjectReference.Create(new TestDTO // Return by ref + { + StringVal = dtoByRef.StringVal.ToUpperInvariant(), + IntVal = dtoByRef.IntVal * 2, + }) + }); + } + + [JSInvokable] + public async ValueTask InvokableAsyncMethodReturningValueTaskNonGeneric() + { + await Task.CompletedTask; + return; + } + public class InvokableAsyncMethodResult { public TestDTO SomeDTO { get; set; } diff --git a/src/Middleware/HttpLogging/src/W3CLoggerProcessor.cs b/src/Middleware/HttpLogging/src/W3CLoggerProcessor.cs index cbd0f5247b..bee9b496f7 100644 --- a/src/Middleware/HttpLogging/src/W3CLoggerProcessor.cs +++ b/src/Middleware/HttpLogging/src/W3CLoggerProcessor.cs @@ -22,7 +22,7 @@ internal class W3CLoggerProcessor : FileLoggerProcessor { await WriteMessageAsync("#Version: 1.0", streamWriter, cancellationToken); - await WriteMessageAsync("#Start-Date: " + DateTimeOffset.UtcNow.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture), streamWriter, cancellationToken); + await WriteMessageAsync("#Start-Date: " + DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture), streamWriter, cancellationToken); await WriteMessageAsync(GetFieldsDirective(), streamWriter, cancellationToken); } diff --git a/src/Middleware/HttpLogging/test/W3CLoggerTests.cs b/src/Middleware/HttpLogging/test/W3CLoggerTests.cs index 5478f4fd9c..d8d976caa3 100644 --- a/src/Middleware/HttpLogging/test/W3CLoggerTests.cs +++ b/src/Middleware/HttpLogging/test/W3CLoggerTests.cs @@ -39,7 +39,9 @@ public class W3CLoggerTests Assert.StartsWith("#Start-Date: ", lines[1]); var startDate = DateTime.Parse(lines[1].Substring(13), CultureInfo.InvariantCulture); // Assert that the log was written in the last 10 seconds - Assert.True(now.Subtract(startDate).TotalSeconds < 10); + // W3CLogger writes start-time to second precision, so delta could be as low as -0.999... + var delta = startDate.Subtract(now).TotalSeconds; + Assert.InRange(delta, -1, 10); Assert.Equal("#Fields: date time", lines[2]); @@ -80,7 +82,9 @@ public class W3CLoggerTests Assert.StartsWith("#Start-Date: ", lines[1]); var startDate = DateTime.Parse(lines[1].Substring(13), CultureInfo.InvariantCulture); // Assert that the log was written in the last 10 seconds - Assert.True(now.Subtract(startDate).TotalSeconds < 10); + // W3CLogger writes start-time to second precision, so delta could be as low as -0.999... + var delta = startDate.Subtract(now).TotalSeconds; + Assert.InRange(delta, -1, 10); Assert.Equal("#Fields: cs-uri-query sc-status cs-host", lines[2]); Assert.Equal("- - -", lines[3]); diff --git a/src/Middleware/HttpLogging/test/W3CLoggingMiddlewareTests.cs b/src/Middleware/HttpLogging/test/W3CLoggingMiddlewareTests.cs index 5146473998..9876620112 100644 --- a/src/Middleware/HttpLogging/test/W3CLoggingMiddlewareTests.cs +++ b/src/Middleware/HttpLogging/test/W3CLoggingMiddlewareTests.cs @@ -95,7 +95,9 @@ public class W3CLoggingMiddlewareTests Assert.StartsWith("#Start-Date: ", lines[1]); var startDate = DateTime.Parse(lines[1].Substring(13), CultureInfo.InvariantCulture); // Assert that the log was written in the last 10 seconds - Assert.True(now.Subtract(startDate).TotalSeconds < 10); + // W3CLogger writes start-time to second precision, so delta could be as low as -0.999... + var delta = startDate.Subtract(now).TotalSeconds; + Assert.InRange(delta, -1, 10); Assert.Equal("#Fields: date time c-ip s-computername s-ip s-port cs-method cs-uri-stem cs-uri-query sc-status time-taken cs-version cs-host cs(User-Agent) cs(Referer)", lines[2]); Assert.DoesNotContain(lines[3], "Snickerdoodle"); @@ -129,7 +131,9 @@ public class W3CLoggingMiddlewareTests Assert.StartsWith("#Start-Date: ", lines[1]); var startDate = DateTime.Parse(lines[1].Substring(13), CultureInfo.InvariantCulture); // Assert that the log was written in the last 10 seconds - Assert.True(now.Subtract(startDate).TotalSeconds < 10); + // W3CLogger writes start-time to second precision, so delta could be as low as -0.999... + var delta = startDate.Subtract(now).TotalSeconds; + Assert.InRange(delta, -1, 10); Assert.Equal("#Fields: time-taken", lines[2]); double num; diff --git a/src/Mvc/Mvc.Testing/src/WebApplicationFactoryClientOptions.cs b/src/Mvc/Mvc.Testing/src/WebApplicationFactoryClientOptions.cs index 4809eb44d1..177bb8ef5b 100644 --- a/src/Mvc/Mvc.Testing/src/WebApplicationFactoryClientOptions.cs +++ b/src/Mvc/Mvc.Testing/src/WebApplicationFactoryClientOptions.cs @@ -42,7 +42,7 @@ public class WebApplicationFactoryClientOptions /// <see cref="WebApplicationFactory{TEntryPoint}.CreateClient(WebApplicationFactoryClientOptions)"/> /// should automatically follow redirect responses. /// The default is <c>true</c>. - /// /// </summary> + /// </summary> public bool AllowAutoRedirect { get; set; } = true; /// <summary> diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/dotnetcli.host.json index 3c34f96f85..02abad32e7 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/dotnetcli.host.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/dotnetcli.host.json @@ -85,6 +85,10 @@ "CallsMicrosoftGraph": { "longName": "calls-graph", "shortName": "" + }, + "UseProgramMain": { + "longName": "use-program-main", + "shortName": "" } }, "usageExamples": [ diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/ide.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/ide.host.json index e891e5f2df..947fd0caa5 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/ide.host.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/ide.host.json @@ -43,6 +43,12 @@ "useHttps": true } ], + "symbolInfo": [ + { + "id": "UseProgramMain", + "isVisible": true + } + ], "disableHttpsSymbol": "NoHttps", "supportsDocker": true } diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.cs.json b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.cs.json index 0d63cde75a..93b827b9d7 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.cs.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.cs.json @@ -34,6 +34,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.de.json b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.de.json index 0d63cde75a..93b827b9d7 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.de.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.de.json @@ -34,6 +34,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.en.json b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.en.json index 0d63cde75a..24cfab2ca6 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.en.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.en.json @@ -34,6 +34,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Do not use top-level statements", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.es.json b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.es.json index 0d63cde75a..93b827b9d7 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.es.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.es.json @@ -34,6 +34,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.fr.json b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.fr.json index 0d63cde75a..93b827b9d7 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.fr.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.fr.json @@ -34,6 +34,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.it.json b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.it.json index 0d63cde75a..93b827b9d7 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.it.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.it.json @@ -34,6 +34,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.ja.json b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.ja.json index 0d63cde75a..93b827b9d7 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.ja.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.ja.json @@ -34,6 +34,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.ko.json b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.ko.json index 0d63cde75a..93b827b9d7 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.ko.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.ko.json @@ -34,6 +34,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.pl.json b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.pl.json index 0d63cde75a..93b827b9d7 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.pl.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.pl.json @@ -34,6 +34,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.pt-BR.json b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.pt-BR.json index 0d63cde75a..93b827b9d7 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.pt-BR.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.pt-BR.json @@ -34,6 +34,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.ru.json b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.ru.json index 0d63cde75a..93b827b9d7 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.ru.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.ru.json @@ -34,6 +34,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.tr.json b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.tr.json index 0d63cde75a..93b827b9d7 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.tr.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.tr.json @@ -34,6 +34,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.zh-Hans.json b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.zh-Hans.json index 0d63cde75a..93b827b9d7 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.zh-Hans.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.zh-Hans.json @@ -34,6 +34,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.zh-Hant.json b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.zh-Hant.json index 0d63cde75a..93b827b9d7 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.zh-Hant.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/localize/templatestrings.zh-Hant.json @@ -34,6 +34,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/template.json index 864f81dae0..0189a641b7 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/template.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/template.json @@ -35,6 +35,21 @@ ], "modifiers": [ { + "condition": "(!UseProgramMain)", + "exclude": [ + "Program.Main.cs" + ] + }, + { + "condition": "(UseProgramMain)", + "exclude": [ + "Program.cs" + ], + "rename": { + "Program.Main.cs": "Program.cs" + } + }, + { "condition": "(!IndividualLocalAuth || UseLocalDB)", "exclude": [ "app.db" @@ -490,6 +505,13 @@ "datatype": "bool", "description": "If specified, skips the automatic restore of the project on create.", "defaultValue": "false" + }, + "UseProgramMain": { + "type": "parameter", + "datatype": "bool", + "defaultValue": "false", + "displayName": "Do not use top-level statements", + "description": "Whether to generate an explicit Program class and Main method instead of top-level statements." } }, "primaryOutputs": [ diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/Program.Main.cs new file mode 100644 index 0000000000..92eb45d80a --- /dev/null +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/Program.Main.cs @@ -0,0 +1,169 @@ +#if (OrganizationalAuth || IndividualB2CAuth) +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.OpenIdConnect; +using Microsoft.Identity.Web; +using Microsoft.Identity.Web.UI; +#endif +#if (WindowsAuth) +using Microsoft.AspNetCore.Authentication.Negotiate; +#endif +#if (OrganizationalAuth) +#if (MultiOrgAuth) +using Microsoft.AspNetCore.Authentication.OpenIdConnect; +#endif +using Microsoft.AspNetCore.Authorization; +#endif +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Web; +#if (IndividualLocalAuth) +using Microsoft.AspNetCore.Components.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity.UI; +#endif +#if (OrganizationalAuth) +using Microsoft.AspNetCore.Mvc.Authorization; +#endif +#if (IndividualLocalAuth) +using Microsoft.EntityFrameworkCore; +#endif +#if (GenerateGraph) +using Graph = Microsoft.Graph; +#endif +#if(MultiOrgAuth) +using Microsoft.IdentityModel.Tokens; +#endif +#if (IndividualLocalAuth) +using BlazorServerWeb_CSharp.Areas.Identity; +#endif +using BlazorServerWeb_CSharp.Data; + +namespace Company.WebApplication1; + +public class Program +{ + public static void Main(string[] args) + { + var builder = WebApplication.CreateBuilder(args); + + // Add services to the container. + #if (IndividualLocalAuth) + var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found."); + builder.Services.AddDbContext<ApplicationDbContext>(options => + #if (UseLocalDB) + options.UseSqlServer(connectionString)); + #else + options.UseSqlite(connectionString)); + #endif + builder.Services.AddDatabaseDeveloperPageExceptionFilter(); + builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true) + .AddEntityFrameworkStores<ApplicationDbContext>(); + #elif (OrganizationalAuth) + #if (GenerateApiOrGraph) + var initialScopes = builder.Configuration["DownstreamApi:Scopes"]?.Split(' '); + + #endif + builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) + #if (GenerateApiOrGraph) + .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd")) + .EnableTokenAcquisitionToCallDownstreamApi(initialScopes) + #if (GenerateApi) + .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi")) + #endif + #if (GenerateGraph) + .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi")) + #endif + .AddInMemoryTokenCaches(); + #else + .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd")); + #endif + #elif (IndividualB2CAuth) + #if (GenerateApi) + var initialScopes = builder.Configuration["DownstreamApi:Scopes"]?.Split(' '); + + #endif + builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) + #if (GenerateApi) + .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAdB2C")) + .EnableTokenAcquisitionToCallDownstreamApi(initialScopes) + .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi")) + .AddInMemoryTokenCaches(); + #else + .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAdB2C")); + #endif + #endif + #if (OrganizationalAuth || IndividualB2CAuth) + builder.Services.AddControllersWithViews() + .AddMicrosoftIdentityUI(); + + builder.Services.AddAuthorization(options => + { + // By default, all incoming requests will be authorized according to the default policy + options.FallbackPolicy = options.DefaultPolicy; + }); + + #elif (WindowsAuth) + builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme) + .AddNegotiate(); + + builder.Services.AddAuthorization(options => + { + // By default, all incoming requests will be authorized according to the default policy. + options.FallbackPolicy = options.DefaultPolicy; + }); + + #endif + builder.Services.AddRazorPages(); + #if (OrganizationalAuth || IndividualB2CAuth) + builder.Services.AddServerSideBlazor() + .AddMicrosoftIdentityConsentHandler(); + #else + builder.Services.AddServerSideBlazor(); + #endif + #if (IndividualLocalAuth) + builder.Services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<IdentityUser>>(); + #endif + builder.Services.AddSingleton<WeatherForecastService>(); + + var app = builder.Build(); + + // Configure the HTTP request pipeline. + #if (IndividualLocalAuth) + if (app.Environment.IsDevelopment()) + { + app.UseMigrationsEndPoint(); + } + else + #else + if (!app.Environment.IsDevelopment()) + #endif + { + app.UseExceptionHandler("/Error"); + #if (RequiresHttps) + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + } + + app.UseHttpsRedirection(); + #else + } + + #endif + + app.UseStaticFiles(); + + app.UseRouting(); + + #if (OrganizationalAuth || IndividualAuth || WindowsAuth) + app.UseAuthentication(); + app.UseAuthorization(); + + #endif + #if (OrganizationalAuth || IndividualAuth) + app.MapControllers(); + #endif + app.MapBlazorHub(); + app.MapFallbackToPage("/_Host"); + + app.Run(); + } +}
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/Shared/NavMenu.CallsMicrosoftGraph.razor b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/Shared/NavMenu.CallsMicrosoftGraph.razor index f1ff97d4b1..1841384590 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/Shared/NavMenu.CallsMicrosoftGraph.razor +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/Shared/NavMenu.CallsMicrosoftGraph.razor @@ -26,7 +26,7 @@ </div> <div class="nav-item px-3"> <NavLink class="nav-link" href="showprofile"> - <span class="oi oi-list-rich" aria-hidden="true"></span> Show profile + <span class="oi oi-person" aria-hidden="true"></span> Show profile </NavLink> </div> </nav> diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/dotnetcli.host.json index 93b2c5a3bc..3d2007dc58 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/dotnetcli.host.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/dotnetcli.host.json @@ -95,6 +95,10 @@ "CallsMicrosoftGraph": { "longName": "calls-graph", "shortName": "" + }, + "UseProgramMain": { + "longName": "use-program-main", + "shortName": "" } } } diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/ide.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/ide.host.json index c48c26c9f4..e4ec39bc5e 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/ide.host.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/ide.host.json @@ -41,6 +41,10 @@ { "id": "PWA", "isVisible": "true" + }, + { + "id": "UseProgramMain", + "isVisible": true } ] } diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.cs.json b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.cs.json index 36d0c9f1e4..7e31298e01 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.cs.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.cs.json @@ -36,6 +36,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'", "postActions/restoreClient/description": "Restore NuGet packages required by this project.", diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.de.json b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.de.json index 36d0c9f1e4..7e31298e01 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.de.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.de.json @@ -36,6 +36,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'", "postActions/restoreClient/description": "Restore NuGet packages required by this project.", diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.en.json b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.en.json index 4cc52e7cdb..530197158d 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.en.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.en.json @@ -36,6 +36,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", + "symbols/UseProgramMain/displayName": "Do not use top-level statements", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'", "postActions/restoreClient/description": "Restore NuGet packages required by this project.", diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.es.json b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.es.json index 36d0c9f1e4..7e31298e01 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.es.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.es.json @@ -36,6 +36,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'", "postActions/restoreClient/description": "Restore NuGet packages required by this project.", diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.fr.json b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.fr.json index 36d0c9f1e4..7e31298e01 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.fr.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.fr.json @@ -36,6 +36,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'", "postActions/restoreClient/description": "Restore NuGet packages required by this project.", diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.it.json b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.it.json index 36d0c9f1e4..7e31298e01 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.it.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.it.json @@ -36,6 +36,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'", "postActions/restoreClient/description": "Restore NuGet packages required by this project.", diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.ja.json b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.ja.json index 36d0c9f1e4..7e31298e01 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.ja.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.ja.json @@ -36,6 +36,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'", "postActions/restoreClient/description": "Restore NuGet packages required by this project.", diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.ko.json b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.ko.json index 36d0c9f1e4..7e31298e01 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.ko.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.ko.json @@ -36,6 +36,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'", "postActions/restoreClient/description": "Restore NuGet packages required by this project.", diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.pl.json b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.pl.json index 36d0c9f1e4..7e31298e01 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.pl.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.pl.json @@ -36,6 +36,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'", "postActions/restoreClient/description": "Restore NuGet packages required by this project.", diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.pt-BR.json b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.pt-BR.json index 36d0c9f1e4..7e31298e01 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.pt-BR.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.pt-BR.json @@ -36,6 +36,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'", "postActions/restoreClient/description": "Restore NuGet packages required by this project.", diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.ru.json b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.ru.json index 36d0c9f1e4..7e31298e01 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.ru.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.ru.json @@ -36,6 +36,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'", "postActions/restoreClient/description": "Restore NuGet packages required by this project.", diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.tr.json b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.tr.json index 36d0c9f1e4..7e31298e01 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.tr.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.tr.json @@ -36,6 +36,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'", "postActions/restoreClient/description": "Restore NuGet packages required by this project.", diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.zh-Hans.json b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.zh-Hans.json index 36d0c9f1e4..7e31298e01 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.zh-Hans.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.zh-Hans.json @@ -36,6 +36,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'", "postActions/restoreClient/description": "Restore NuGet packages required by this project.", diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.zh-Hant.json b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.zh-Hant.json index 36d0c9f1e4..7e31298e01 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.zh-Hant.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/localize/templatestrings.zh-Hant.json @@ -36,6 +36,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C without and ASP.NET Core host is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'", "postActions/restoreClient/description": "Restore NuGet packages required by this project.", diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/template.json index 84db26de74..101f868b87 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/template.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/template.json @@ -95,6 +95,24 @@ ] }, { + "condition": "(!UseProgramMain)", + "exclude": [ + "Server/Program.Main.cs", + "Client/Program.Main.cs" + ] + }, + { + "condition": "(UseProgramMain)", + "exclude": [ + "Server/Program.cs", + "Client/Program.cs" + ], + "rename": { + "Server/Program.Main.cs": "Server/Program.cs", + "Client/Program.Main.cs": "Client/Program.cs" + } + }, + { "condition": "(!IndividualLocalAuth || UseLocalDB)", "exclude": [ "Server/app.db" @@ -593,6 +611,13 @@ "GenerateApiOrGraph": { "type": "computed", "value": "(GenerateApi || GenerateGraph)" + }, + "UseProgramMain": { + "type": "parameter", + "datatype": "bool", + "defaultValue": "false", + "displayName": "Do not use top-level statements", + "description": "Whether to generate an explicit Program class and Main method instead of top-level statements." } }, "tags": { diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/Program.Main.cs new file mode 100644 index 0000000000..8b870e5dc9 --- /dev/null +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/Program.Main.cs @@ -0,0 +1,69 @@ +using Microsoft.AspNetCore.Components.Web; +#if (!NoAuth && Hosted) +using Microsoft.AspNetCore.Components.WebAssembly.Authentication; +#endif +using Microsoft.AspNetCore.Components.WebAssembly.Hosting; +#if (Hosted) +using ComponentsWebAssembly_CSharp.Client; +#else +using ComponentsWebAssembly_CSharp; +#endif + +namespace Company.WebApplication1; + +public class Program +{ + public static async Task Main(string[] args) + { + var builder = WebAssemblyHostBuilder.CreateDefault(args); + builder.RootComponents.Add<App>("#app"); + builder.RootComponents.Add<HeadOutlet>("head::after"); + + #if (!Hosted || NoAuth) + builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); + #else + builder.Services.AddHttpClient("ComponentsWebAssembly_CSharp.ServerAPI", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)) + .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>(); + + // Supply HttpClient instances that include access tokens when making requests to the server project + builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("ComponentsWebAssembly_CSharp.ServerAPI")); + #endif + #if(!NoAuth) + + #endif + #if (IndividualLocalAuth) + #if (Hosted) + builder.Services.AddApiAuthorization(); + #else + builder.Services.AddOidcAuthentication(options => + { + #if(MissingAuthority) + // Configure your authentication provider options here. + // For more information, see https://aka.ms/blazor-standalone-auth + #endif + builder.Configuration.Bind("Local", options.ProviderOptions); + }); + #endif + #endif + #if (IndividualB2CAuth) + builder.Services.AddMsalAuthentication(options => + { + builder.Configuration.Bind("AzureAdB2C", options.ProviderOptions.Authentication); + #if (Hosted) + options.ProviderOptions.DefaultAccessTokenScopes.Add("https://qualified.domain.name/api.id.uri/api-scope"); + #endif + }); + #endif + #if(OrganizationalAuth) + builder.Services.AddMsalAuthentication(options => + { + builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication); + #if (Hosted) + options.ProviderOptions.DefaultAccessTokenScopes.Add("api://api.id.uri/api-scope"); + #endif + }); + #endif + + await builder.Build().RunAsync(); + } +} diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/Shared/NavMenu.CallsMicrosoftGraph.razor b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/Shared/NavMenu.CallsMicrosoftGraph.razor index bf3861b243..429950805b 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/Shared/NavMenu.CallsMicrosoftGraph.razor +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/Shared/NavMenu.CallsMicrosoftGraph.razor @@ -26,7 +26,7 @@ </div> <div class="nav-item px-3"> <NavLink class="nav-link" href="showProfile"> - <span class="oi oi-list-rich" aria-hidden="true"></span> Show Profile + <span class="oi oi-person" aria-hidden="true"></span> Show Profile </NavLink> </div> </nav> diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/wwwroot/sample-data/weather.json b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/wwwroot/sample-data/weather.json index 06463c02f1..b7459733f9 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/wwwroot/sample-data/weather.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/wwwroot/sample-data/weather.json @@ -1,26 +1,26 @@ [ { - "date": "2018-05-06", + "date": "2022-01-06", "temperatureC": 1, "summary": "Freezing" }, { - "date": "2018-05-07", + "date": "2022-01-07", "temperatureC": 14, "summary": "Bracing" }, { - "date": "2018-05-08", + "date": "2022-01-08", "temperatureC": -13, "summary": "Freezing" }, { - "date": "2018-05-09", + "date": "2022-01-09", "temperatureC": -16, "summary": "Balmy" }, { - "date": "2018-05-10", + "date": "2022-01-10", "temperatureC": -2, "summary": "Chilly" } diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Server/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Server/Program.Main.cs new file mode 100644 index 0000000000..31835439cd --- /dev/null +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Server/Program.Main.cs @@ -0,0 +1,125 @@ +#if (OrganizationalAuth || IndividualB2CAuth || IndividualLocalAuth) +using Microsoft.AspNetCore.Authentication; +#endif +#if (OrganizationalAuth || IndividualB2CAuth) +using Microsoft.AspNetCore.Authentication.JwtBearer; +#endif +using Microsoft.AspNetCore.ResponseCompression; +#if (IndividualLocalAuth) +using Microsoft.EntityFrameworkCore; +#endif +#if (GenerateGraph) +using Graph = Microsoft.Graph; +#endif +#if (OrganizationalAuth || IndividualB2CAuth) +using Microsoft.Identity.Web; +#endif +#if (IndividualLocalAuth) +using ComponentsWebAssembly_CSharp.Server.Data; +using ComponentsWebAssembly_CSharp.Server.Models; +#endif + +namespace Company.WebApplication1; + +public class Program +{ + public static void Main(string[] args) + { + var builder = WebApplication.CreateBuilder(args); + + // Add services to the container. + #if (IndividualLocalAuth) + var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found."); + builder.Services.AddDbContext<ApplicationDbContext>(options => + #if (UseLocalDB) + options.UseSqlServer(connectionString)); + #else + options.UseSqlite(connectionString)); + #endif + builder.Services.AddDatabaseDeveloperPageExceptionFilter(); + + builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true) + .AddEntityFrameworkStores<ApplicationDbContext>(); + + builder.Services.AddIdentityServer() + .AddApiAuthorization<ApplicationUser, ApplicationDbContext>(); + + builder.Services.AddAuthentication() + .AddIdentityServerJwt(); + #endif + #if (OrganizationalAuth) + builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) + #if (GenerateApiOrGraph) + .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd")) + .EnableTokenAcquisitionToCallDownstreamApi() + #if (GenerateApi) + .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi")) + #endif + #if (GenerateGraph) + .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi")) + #endif + .AddInMemoryTokenCaches(); + #else + .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd")); + #endif + #elif (IndividualB2CAuth) + builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) + #if (GenerateApi) + .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAdB2C")) + .EnableTokenAcquisitionToCallDownstreamApi() + .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi")) + .AddInMemoryTokenCaches(); + #else + .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAdB2C")); + #endif + #endif + + builder.Services.AddControllersWithViews(); + builder.Services.AddRazorPages(); + + var app = builder.Build(); + + // Configure the HTTP request pipeline. + if (app.Environment.IsDevelopment()) + { + #if (IndividualLocalAuth) + app.UseMigrationsEndPoint(); + #endif + app.UseWebAssemblyDebugging(); + } + else + { + app.UseExceptionHandler("/Error"); + #if (RequiresHttps) + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + #endif + } + + #if (RequiresHttps) + app.UseHttpsRedirection(); + + #endif + app.UseBlazorFrameworkFiles(); + app.UseStaticFiles(); + + app.UseRouting(); + + #if (IndividualLocalAuth) + app.UseIdentityServer(); + #endif + #if (OrganizationalAuth || IndividualAuth) + app.UseAuthentication(); + #endif + #if (!NoAuth) + app.UseAuthorization(); + + #endif + + app.MapRazorPages(); + app.MapControllers(); + app.MapFallbackToFile("index.html"); + + app.Run(); + } +} diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/dotnetcli.host.json index d97858472b..6f4f4fb893 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/dotnetcli.host.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/dotnetcli.host.json @@ -27,6 +27,10 @@ "NoHttps": { "longName": "no-https", "shortName": "" + }, + "UseProgramMain": { + "longName": "use-program-main", + "shortName": "" } }, "usageExamples": [ diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/ide.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/ide.host.json index 751a95c5b2..f30c4753e2 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/ide.host.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/ide.host.json @@ -20,5 +20,11 @@ "useHttps": true } ], + "symbolInfo": [ + { + "id": "UseProgramMain", + "isVisible": true + } + ], "disableHttpsSymbol": "NoHttps" } diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.cs.json b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.cs.json index f0366911c0..95327d453e 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.cs.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.cs.json @@ -11,6 +11,8 @@ "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/NoHttps/description": "Whether to turn off HTTPS. This option only applies if Individual, IndividualB2C, SingleOrg, or MultiOrg aren't used for --auth.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.de.json b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.de.json index f0366911c0..95327d453e 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.de.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.de.json @@ -11,6 +11,8 @@ "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/NoHttps/description": "Whether to turn off HTTPS. This option only applies if Individual, IndividualB2C, SingleOrg, or MultiOrg aren't used for --auth.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.en.json b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.en.json index f0366911c0..764a457bb1 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.en.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.en.json @@ -11,6 +11,8 @@ "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/NoHttps/description": "Whether to turn off HTTPS. This option only applies if Individual, IndividualB2C, SingleOrg, or MultiOrg aren't used for --auth.", + "symbols/UseProgramMain/displayName": "Do not use top-level statements", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.es.json b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.es.json index f0366911c0..95327d453e 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.es.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.es.json @@ -11,6 +11,8 @@ "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/NoHttps/description": "Whether to turn off HTTPS. This option only applies if Individual, IndividualB2C, SingleOrg, or MultiOrg aren't used for --auth.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.fr.json b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.fr.json index f0366911c0..95327d453e 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.fr.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.fr.json @@ -11,6 +11,8 @@ "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/NoHttps/description": "Whether to turn off HTTPS. This option only applies if Individual, IndividualB2C, SingleOrg, or MultiOrg aren't used for --auth.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.it.json b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.it.json index f0366911c0..95327d453e 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.it.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.it.json @@ -11,6 +11,8 @@ "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/NoHttps/description": "Whether to turn off HTTPS. This option only applies if Individual, IndividualB2C, SingleOrg, or MultiOrg aren't used for --auth.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.ja.json b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.ja.json index f0366911c0..95327d453e 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.ja.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.ja.json @@ -11,6 +11,8 @@ "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/NoHttps/description": "Whether to turn off HTTPS. This option only applies if Individual, IndividualB2C, SingleOrg, or MultiOrg aren't used for --auth.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.ko.json b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.ko.json index f0366911c0..95327d453e 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.ko.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.ko.json @@ -11,6 +11,8 @@ "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/NoHttps/description": "Whether to turn off HTTPS. This option only applies if Individual, IndividualB2C, SingleOrg, or MultiOrg aren't used for --auth.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.pl.json b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.pl.json index f0366911c0..95327d453e 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.pl.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.pl.json @@ -11,6 +11,8 @@ "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/NoHttps/description": "Whether to turn off HTTPS. This option only applies if Individual, IndividualB2C, SingleOrg, or MultiOrg aren't used for --auth.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.pt-BR.json b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.pt-BR.json index f0366911c0..95327d453e 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.pt-BR.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.pt-BR.json @@ -11,6 +11,8 @@ "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/NoHttps/description": "Whether to turn off HTTPS. This option only applies if Individual, IndividualB2C, SingleOrg, or MultiOrg aren't used for --auth.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.ru.json b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.ru.json index f0366911c0..95327d453e 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.ru.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.ru.json @@ -11,6 +11,8 @@ "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/NoHttps/description": "Whether to turn off HTTPS. This option only applies if Individual, IndividualB2C, SingleOrg, or MultiOrg aren't used for --auth.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.tr.json b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.tr.json index f0366911c0..95327d453e 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.tr.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.tr.json @@ -11,6 +11,8 @@ "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/NoHttps/description": "Whether to turn off HTTPS. This option only applies if Individual, IndividualB2C, SingleOrg, or MultiOrg aren't used for --auth.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.zh-Hans.json b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.zh-Hans.json index f0366911c0..95327d453e 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.zh-Hans.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.zh-Hans.json @@ -11,6 +11,8 @@ "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/NoHttps/description": "Whether to turn off HTTPS. This option only applies if Individual, IndividualB2C, SingleOrg, or MultiOrg aren't used for --auth.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.zh-Hant.json b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.zh-Hant.json index f0366911c0..95327d453e 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.zh-Hant.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/localize/templatestrings.zh-Hant.json @@ -11,6 +11,8 @@ "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/NoHttps/description": "Whether to turn off HTTPS. This option only applies if Individual, IndividualB2C, SingleOrg, or MultiOrg aren't used for --auth.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/template.json index ae82a87026..9accfeb934 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/template.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/template.json @@ -29,6 +29,21 @@ "exclude": [ "Properties/launchSettings.json" ] + }, + { + "condition": "(!UseProgramMain)", + "exclude": [ + "Program.Main.cs" + ] + }, + { + "condition": "(UseProgramMain)", + "exclude": [ + "Program.cs" + ], + "rename": { + "Program.Main.cs": "Program.cs" + } } ] } @@ -156,6 +171,13 @@ "datatype": "bool", "defaultValue": "false", "description": "Whether to turn off HTTPS. This option only applies if Individual, IndividualB2C, SingleOrg, or MultiOrg aren't used for --auth." + }, + "UseProgramMain": { + "type": "parameter", + "datatype": "bool", + "defaultValue": "false", + "displayName": "Do not use top-level statements", + "description": "Whether to generate an explicit Program class and Main method instead of top-level statements." } }, "primaryOutputs": [ diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/Program.Main.cs new file mode 100644 index 0000000000..6a10649982 --- /dev/null +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/Program.Main.cs @@ -0,0 +1,14 @@ +namespace Company.WebApplication1; + +public class Program +{ + public static void Main(string[] args) + { + var builder = WebApplication.CreateBuilder(args); + var app = builder.Build(); + + app.MapGet("/", () => "Hello World!"); + + app.Run(); + } +} diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/dotnetcli.host.json index 684bc1e734..ded3cbf35f 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/dotnetcli.host.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/dotnetcli.host.json @@ -14,6 +14,10 @@ "ExcludeLaunchSettings": { "longName": "exclude-launch-settings", "shortName": "" + }, + "UseProgramMain": { + "longName": "use-program-main", + "shortName": "" } }, "usageExamples": [ diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/ide.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/ide.host.json index 2cb4190951..5c3a869512 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/ide.host.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/ide.host.json @@ -2,5 +2,11 @@ "$schema": "http://json.schemastore.org/vs-2017.3.host", "order": 500, "icon": "ide/gRPC.png", - "supportsDocker": true + "supportsDocker": true, + "symbolInfo": [ + { + "id": "UseProgramMain", + "isVisible": true + } + ] } diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.cs.json b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.cs.json index 64465ca34a..eec915b973 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.cs.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.cs.json @@ -8,6 +8,8 @@ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.", "symbols/kestrelHttpsPort/description": "Port number to use for the HTTPS endpoint in launchSettings.json. This option is only applicable when the parameter no-https is not used (no-https will be ignored if either IndividualAuth or OrganizationalAuth is used).", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.de.json b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.de.json index 64465ca34a..eec915b973 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.de.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.de.json @@ -8,6 +8,8 @@ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.", "symbols/kestrelHttpsPort/description": "Port number to use for the HTTPS endpoint in launchSettings.json. This option is only applicable when the parameter no-https is not used (no-https will be ignored if either IndividualAuth or OrganizationalAuth is used).", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.en.json b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.en.json index 64465ca34a..a1f2262d3d 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.en.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.en.json @@ -8,6 +8,8 @@ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.", "symbols/kestrelHttpsPort/description": "Port number to use for the HTTPS endpoint in launchSettings.json. This option is only applicable when the parameter no-https is not used (no-https will be ignored if either IndividualAuth or OrganizationalAuth is used).", + "symbols/UseProgramMain/displayName": "Do not use top-level statements", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.es.json b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.es.json index 64465ca34a..eec915b973 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.es.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.es.json @@ -8,6 +8,8 @@ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.", "symbols/kestrelHttpsPort/description": "Port number to use for the HTTPS endpoint in launchSettings.json. This option is only applicable when the parameter no-https is not used (no-https will be ignored if either IndividualAuth or OrganizationalAuth is used).", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.fr.json b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.fr.json index 64465ca34a..eec915b973 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.fr.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.fr.json @@ -8,6 +8,8 @@ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.", "symbols/kestrelHttpsPort/description": "Port number to use for the HTTPS endpoint in launchSettings.json. This option is only applicable when the parameter no-https is not used (no-https will be ignored if either IndividualAuth or OrganizationalAuth is used).", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.it.json b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.it.json index 64465ca34a..eec915b973 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.it.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.it.json @@ -8,6 +8,8 @@ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.", "symbols/kestrelHttpsPort/description": "Port number to use for the HTTPS endpoint in launchSettings.json. This option is only applicable when the parameter no-https is not used (no-https will be ignored if either IndividualAuth or OrganizationalAuth is used).", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.ja.json b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.ja.json index 64465ca34a..eec915b973 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.ja.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.ja.json @@ -8,6 +8,8 @@ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.", "symbols/kestrelHttpsPort/description": "Port number to use for the HTTPS endpoint in launchSettings.json. This option is only applicable when the parameter no-https is not used (no-https will be ignored if either IndividualAuth or OrganizationalAuth is used).", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.ko.json b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.ko.json index 64465ca34a..eec915b973 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.ko.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.ko.json @@ -8,6 +8,8 @@ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.", "symbols/kestrelHttpsPort/description": "Port number to use for the HTTPS endpoint in launchSettings.json. This option is only applicable when the parameter no-https is not used (no-https will be ignored if either IndividualAuth or OrganizationalAuth is used).", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.pl.json b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.pl.json index 64465ca34a..eec915b973 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.pl.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.pl.json @@ -8,6 +8,8 @@ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.", "symbols/kestrelHttpsPort/description": "Port number to use for the HTTPS endpoint in launchSettings.json. This option is only applicable when the parameter no-https is not used (no-https will be ignored if either IndividualAuth or OrganizationalAuth is used).", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.pt-BR.json b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.pt-BR.json index 64465ca34a..eec915b973 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.pt-BR.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.pt-BR.json @@ -8,6 +8,8 @@ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.", "symbols/kestrelHttpsPort/description": "Port number to use for the HTTPS endpoint in launchSettings.json. This option is only applicable when the parameter no-https is not used (no-https will be ignored if either IndividualAuth or OrganizationalAuth is used).", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.ru.json b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.ru.json index 64465ca34a..eec915b973 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.ru.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.ru.json @@ -8,6 +8,8 @@ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.", "symbols/kestrelHttpsPort/description": "Port number to use for the HTTPS endpoint in launchSettings.json. This option is only applicable when the parameter no-https is not used (no-https will be ignored if either IndividualAuth or OrganizationalAuth is used).", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.tr.json b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.tr.json index 64465ca34a..eec915b973 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.tr.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.tr.json @@ -8,6 +8,8 @@ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.", "symbols/kestrelHttpsPort/description": "Port number to use for the HTTPS endpoint in launchSettings.json. This option is only applicable when the parameter no-https is not used (no-https will be ignored if either IndividualAuth or OrganizationalAuth is used).", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.zh-Hans.json b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.zh-Hans.json index 64465ca34a..eec915b973 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.zh-Hans.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.zh-Hans.json @@ -8,6 +8,8 @@ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.", "symbols/kestrelHttpsPort/description": "Port number to use for the HTTPS endpoint in launchSettings.json. This option is only applicable when the parameter no-https is not used (no-https will be ignored if either IndividualAuth or OrganizationalAuth is used).", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.zh-Hant.json b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.zh-Hant.json index 64465ca34a..eec915b973 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.zh-Hant.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/localize/templatestrings.zh-Hant.json @@ -8,6 +8,8 @@ "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", "symbols/kestrelHttpPort/description": "Port number to use for the HTTP endpoint in launchSettings.json.", "symbols/kestrelHttpsPort/description": "Port number to use for the HTTPS endpoint in launchSettings.json. This option is only applicable when the parameter no-https is not used (no-https will be ignored if either IndividualAuth or OrganizationalAuth is used).", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/template.json index 8e17381b92..9b1f90bc5b 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/template.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/template.json @@ -26,6 +26,21 @@ "exclude": [ "Properties/launchSettings.json" ] + }, + { + "condition": "(!UseProgramMain)", + "exclude": [ + "Program.Main.cs" + ] + }, + { + "condition": "(UseProgramMain)", + "exclude": [ + "Program.cs" + ], + "rename": { + "Program.Main.cs": "Program.cs" + } } ] } @@ -102,6 +117,13 @@ "fallbackVariableName": "kestrelHttpsPortGenerated" }, "replaces": "5001" + }, + "UseProgramMain": { + "type": "parameter", + "datatype": "bool", + "defaultValue": "false", + "displayName": "Do not use top-level statements", + "description": "Whether to generate an explicit Program class and Main method instead of top-level statements." } }, "primaryOutputs": [ diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/Program.Main.cs new file mode 100644 index 0000000000..ec1af1a7e9 --- /dev/null +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/Program.Main.cs @@ -0,0 +1,25 @@ +using GrpcService_CSharp.Services; + +namespace Company.WebApplication1; + +public class Program +{ + public static void Main(string[] args) + { + var builder = WebApplication.CreateBuilder(args); + + // Additional configuration is required to successfully run gRPC on macOS. + // For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682 + + // Add services to the container. + builder.Services.AddGrpc(); + + var app = builder.Build(); + + // Configure the HTTP request pipeline. + app.MapGrpcService<GreeterService>(); + app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909"); + + app.Run(); + } +}
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/dotnetcli.host.json index 6ce1fbe6eb..a00ae64f28 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/dotnetcli.host.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/dotnetcli.host.json @@ -85,6 +85,10 @@ "CallsMicrosoftGraph": { "longName": "calls-graph", "shortName": "" + }, + "UseProgramMain": { + "longName": "use-program-main", + "shortName": "" } }, "usageExamples": [ diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/ide.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/ide.host.json index f176b8df2a..0dc542e09b 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/ide.host.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/ide.host.json @@ -45,7 +45,10 @@ } ], "symbolInfo": [ - + { + "id": "UseProgramMain", + "isVisible": true + } ], "disableHttpsSymbol": "NoHttps" } diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.cs.json b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.cs.json index 390d976d32..815f7d8cab 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.cs.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.cs.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.de.json b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.de.json index 390d976d32..815f7d8cab 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.de.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.de.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.en.json b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.en.json index 390d976d32..d9e25f82e1 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.en.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.en.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Do not use top-level statements", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.es.json b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.es.json index 390d976d32..815f7d8cab 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.es.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.es.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.fr.json b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.fr.json index 390d976d32..815f7d8cab 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.fr.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.fr.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.it.json b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.it.json index 390d976d32..815f7d8cab 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.it.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.it.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.ja.json b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.ja.json index 390d976d32..815f7d8cab 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.ja.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.ja.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.ko.json b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.ko.json index 390d976d32..815f7d8cab 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.ko.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.ko.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.pl.json b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.pl.json index 390d976d32..815f7d8cab 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.pl.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.pl.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.pt-BR.json b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.pt-BR.json index 390d976d32..815f7d8cab 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.pt-BR.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.pt-BR.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.ru.json b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.ru.json index 390d976d32..815f7d8cab 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.ru.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.ru.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.tr.json b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.tr.json index 390d976d32..815f7d8cab 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.tr.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.tr.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.zh-Hans.json b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.zh-Hans.json index 390d976d32..815f7d8cab 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.zh-Hans.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.zh-Hans.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.zh-Hant.json b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.zh-Hant.json index 390d976d32..815f7d8cab 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.zh-Hant.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/localize/templatestrings.zh-Hant.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/template.json index e8d986bdd0..3f42794ce9 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/template.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/template.json @@ -94,6 +94,21 @@ "exclude": [ "Data/SqlServer/**" ] + }, + { + "condition": "(!UseProgramMain)", + "exclude": [ + "Program.Main.cs" + ] + }, + { + "condition": "(UseProgramMain)", + "exclude": [ + "Program.cs" + ], + "rename": { + "Program.Main.cs": "Program.cs" + } } ] } @@ -406,6 +421,13 @@ "GenerateApiOrGraph": { "type": "computed", "value": "(GenerateApi || GenerateGraph)" + }, + "UseProgramMain": { + "type": "parameter", + "datatype": "bool", + "defaultValue": "false", + "displayName": "Do not use top-level statements", + "description": "Whether to generate an explicit Program class and Main method instead of top-level statements." } }, "primaryOutputs": [ diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/Program.Main.cs new file mode 100644 index 0000000000..3a1a1d68cc --- /dev/null +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/Program.Main.cs @@ -0,0 +1,155 @@ +#if (OrganizationalAuth || IndividualB2CAuth) +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.OpenIdConnect; +using Microsoft.AspNetCore.Authorization; +#endif +#if (WindowsAuth) +using Microsoft.AspNetCore.Authentication.Negotiate; +#endif +#if (IndividualLocalAuth) +using Microsoft.AspNetCore.Identity; +#endif +#if (OrganizationalAuth) +using Microsoft.AspNetCore.Mvc.Authorization; +#endif +#if (IndividualLocalAuth) +using Microsoft.EntityFrameworkCore; +#endif +#if (OrganizationalAuth || IndividualB2CAuth) +using Microsoft.Identity.Web; +using Microsoft.Identity.Web.UI; +#endif +#if (MultiOrgAuth) +using Microsoft.IdentityModel.Tokens; +#endif +#if (GenerateGraph) +using Graph = Microsoft.Graph; +#endif +#if (IndividualLocalAuth) +using Company.WebApplication1.Data; +#endif +#if (OrganizationalAuth || IndividualB2CAuth || IndividualLocalAuth || MultiOrgAuth || GenerateGraph || WindowsAuth) + +#endif +namespace Company.WebApplication1; + +public class Program +{ + public static void Main(string[] args) + { + var builder = WebApplication.CreateBuilder(args); + + // Add services to the container. + #if (IndividualLocalAuth) + var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found."); + builder.Services.AddDbContext<ApplicationDbContext>(options => + #if (UseLocalDB) + options.UseSqlServer(connectionString)); + #else + options.UseSqlite(connectionString)); + #endif + builder.Services.AddDatabaseDeveloperPageExceptionFilter(); + + builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true) + .AddEntityFrameworkStores<ApplicationDbContext>(); + #elif (OrganizationalAuth) + #if (GenerateApiOrGraph) + var initialScopes = builder.Configuration["DownstreamApi:Scopes"]?.Split(' '); + + #endif + builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) + #if (GenerateApiOrGraph) + .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd")) + .EnableTokenAcquisitionToCallDownstreamApi(initialScopes) + #if (GenerateApi) + .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi")) + #endif + #if (GenerateGraph) + .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi")) + #endif + .AddInMemoryTokenCaches(); + #else + .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd")); + #endif + #elif (IndividualB2CAuth) + #if (GenerateApi) + var initialScopes = builder.Configuration["DownstreamApi:Scopes"]?.Split(' '); + + #endif + builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) + #if (GenerateApi) + .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAdB2C")) + .EnableTokenAcquisitionToCallDownstreamApi(initialScopes) + .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi")) + .AddInMemoryTokenCaches(); + #else + .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAdB2C")); + #endif + #endif + #if (OrganizationalAuth) + + builder.Services.AddAuthorization(options => + { + // By default, all incoming requests will be authorized according to the default policy. + options.FallbackPolicy = options.DefaultPolicy; + }); + builder.Services.AddRazorPages() + .AddMicrosoftIdentityUI(); + #elif (IndividualB2CAuth) + builder.Services.AddRazorPages() + .AddMicrosoftIdentityUI(); + #elif (WindowsAuth) + + builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme) + .AddNegotiate(); + + builder.Services.AddAuthorization(options => + { + // By default, all incoming requests will be authorized according to the default policy. + options.FallbackPolicy = options.DefaultPolicy; + }); + builder.Services.AddRazorPages(); + #else + builder.Services.AddRazorPages(); + #endif + + var app = builder.Build(); + + // Configure the HTTP request pipeline. + #if (IndividualLocalAuth) + if (app.Environment.IsDevelopment()) + { + app.UseMigrationsEndPoint(); + } + else + #else + if (!app.Environment.IsDevelopment()) + #endif + { + app.UseExceptionHandler("/Error"); + #if (RequiresHttps) + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + } + + app.UseHttpsRedirection(); + #else + } + #endif + app.UseStaticFiles(); + + app.UseRouting(); + + #if (OrganizationalAuth || IndividualAuth || WindowsAuth) + app.UseAuthentication(); + #endif + app.UseAuthorization(); + + app.MapRazorPages(); + #if (IndividualB2CAuth || OrganizationalAuth) + app.MapControllers(); + #endif + + app.Run(); + } +}
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/dotnetcli.host.json index 3c34f96f85..02abad32e7 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/dotnetcli.host.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/dotnetcli.host.json @@ -85,6 +85,10 @@ "CallsMicrosoftGraph": { "longName": "calls-graph", "shortName": "" + }, + "UseProgramMain": { + "longName": "use-program-main", + "shortName": "" } }, "usageExamples": [ diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/ide.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/ide.host.json index 12bb6ec5db..995a75bea9 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/ide.host.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/ide.host.json @@ -45,7 +45,10 @@ } ], "symbolInfo": [ - + { + "id": "UseProgramMain", + "isVisible": true + } ], "disableHttpsSymbol": "NoHttps" } diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.cs.json b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.cs.json index 42fc6e65af..9a7972bc95 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.cs.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.cs.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use an Program class and Main method.", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.de.json b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.de.json index 42fc6e65af..9a7972bc95 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.de.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.de.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use an Program class and Main method.", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.en.json b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.en.json index 42fc6e65af..4f01b0e182 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.en.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.en.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Do not use top-level statements", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.es.json b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.es.json index 42fc6e65af..9a7972bc95 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.es.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.es.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use an Program class and Main method.", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.fr.json b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.fr.json index 42fc6e65af..9a7972bc95 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.fr.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.fr.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use an Program class and Main method.", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.it.json b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.it.json index 42fc6e65af..9a7972bc95 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.it.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.it.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use an Program class and Main method.", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.ja.json b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.ja.json index 42fc6e65af..9a7972bc95 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.ja.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.ja.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use an Program class and Main method.", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.ko.json b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.ko.json index 42fc6e65af..9a7972bc95 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.ko.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.ko.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use an Program class and Main method.", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.pl.json b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.pl.json index 42fc6e65af..9a7972bc95 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.pl.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.pl.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use an Program class and Main method.", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.pt-BR.json b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.pt-BR.json index 42fc6e65af..9a7972bc95 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.pt-BR.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.pt-BR.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use an Program class and Main method.", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.ru.json b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.ru.json index 42fc6e65af..9a7972bc95 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.ru.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.ru.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use an Program class and Main method.", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.tr.json b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.tr.json index 42fc6e65af..9a7972bc95 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.tr.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.tr.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use an Program class and Main method.", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.zh-Hans.json b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.zh-Hans.json index 42fc6e65af..9a7972bc95 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.zh-Hans.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.zh-Hans.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use an Program class and Main method.", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.zh-Hant.json b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.zh-Hant.json index 42fc6e65af..9a7972bc95 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.zh-Hant.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/localize/templatestrings.zh-Hant.json @@ -34,6 +34,8 @@ "symbols/CalledApiUrl/description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg or --auth MultiOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg, --auth MultiOrg or --auth IndividualB2C is specified.", + "symbols/UseProgramMain/displayName": "Use an Program class and Main method.", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/template.json index ebc005e25f..a2af2cbbf6 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/template.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/template.json @@ -90,6 +90,21 @@ "exclude": [ "Data/SqlServer/**" ] + }, + { + "condition": "(!UseProgramMain)", + "exclude": [ + "Program.Main.cs" + ] + }, + { + "condition": "(UseProgramMain)", + "exclude": [ + "Program.cs" + ], + "rename": { + "Program.Main.cs": "Program.cs" + } } ] } @@ -402,6 +417,13 @@ "GenerateApiOrGraph": { "type": "computed", "value": "(GenerateApi || GenerateGraph)" + }, + "UseProgramMain": { + "type": "parameter", + "datatype": "bool", + "defaultValue": "false", + "displayName": "Do not use top-level statements", + "description": "Whether to generate an explicit Program class and Main method instead of top-level statements." } }, "primaryOutputs": [ diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/Program.Main.cs new file mode 100644 index 0000000000..5fda9092d0 --- /dev/null +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/Program.Main.cs @@ -0,0 +1,159 @@ +#if (OrganizationalAuth || IndividualB2CAuth) +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Authentication.OpenIdConnect; +#endif +#if (WindowsAuth) +using Microsoft.AspNetCore.Authentication.Negotiate; +#endif +#if (IndividualLocalAuth) +using Microsoft.AspNetCore.Identity; +#endif +#if (OrganizationalAuth) +using Microsoft.AspNetCore.Mvc.Authorization; +#endif +#if (IndividualLocalAuth) +using Microsoft.EntityFrameworkCore; +#endif +#if (OrganizationalAuth || IndividualB2CAuth) +using Microsoft.Identity.Web; +using Microsoft.Identity.Web.UI; +#endif +#if (MultiOrgAuth) +using Microsoft.IdentityModel.Tokens; +#endif +#if (GenerateGraph) +using Graph = Microsoft.Graph; +#endif +#if (IndividualLocalAuth) +using Company.WebApplication1.Data; +#endif +#if (OrganizationalAuth || IndividualB2CAuth || IndividualLocalAuth || MultiOrgAuth || GenerateGraph || WindowsAuth) + +#endif +namespace Company.WebApplication1; + +public class Program +{ + public static void Main(string[] args) + { + var builder = WebApplication.CreateBuilder(args); + + // Add services to the container. + #if (IndividualLocalAuth) + var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found."); + builder.Services.AddDbContext<ApplicationDbContext>(options => + #if (UseLocalDB) + options.UseSqlServer(connectionString)); + #else + options.UseSqlite(connectionString)); + #endif + builder.Services.AddDatabaseDeveloperPageExceptionFilter(); + + builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true) + .AddEntityFrameworkStores<ApplicationDbContext>(); + #elif (OrganizationalAuth) + #if (GenerateApiOrGraph) + var initialScopes = builder.Configuration["DownstreamApi:Scopes"]?.Split(' '); + + #endif + builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) + #if (GenerateApiOrGraph) + .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd")) + .EnableTokenAcquisitionToCallDownstreamApi(initialScopes) + #if (GenerateApi) + .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi")) + #endif + #if (GenerateGraph) + .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi")) + #endif + .AddInMemoryTokenCaches(); + #else + .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd")); + #endif + #elif (IndividualB2CAuth) + #if (GenerateApi) + var initialScopes = builder.Configuration["DownstreamApi:Scopes"]?.Split(' '); + + #endif + builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) + #if (GenerateApi) + .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAdB2C")) + .EnableTokenAcquisitionToCallDownstreamApi(initialScopes) + .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi")) + .AddInMemoryTokenCaches(); + #else + .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAdB2C")); + #endif + #endif + #if (OrganizationalAuth) + + builder.Services.AddControllersWithViews(options => + { + var policy = new AuthorizationPolicyBuilder() + .RequireAuthenticatedUser() + .Build(); + options.Filters.Add(new AuthorizeFilter(policy)); + }); + #else + builder.Services.AddControllersWithViews(); + #endif + #if (OrganizationalAuth || IndividualB2CAuth) + builder.Services.AddRazorPages() + .AddMicrosoftIdentityUI(); + #endif + #if (WindowsAuth) + + builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme) + .AddNegotiate(); + + builder.Services.AddAuthorization(options => + { + // By default, all incoming requests will be authorized according to the default policy. + options.FallbackPolicy = options.DefaultPolicy; + }); + builder.Services.AddRazorPages(); + #endif + + var app = builder.Build(); + + // Configure the HTTP request pipeline. + #if (IndividualLocalAuth) + if (app.Environment.IsDevelopment()) + { + app.UseMigrationsEndPoint(); + } + else + #else + if (!app.Environment.IsDevelopment()) + #endif + { + app.UseExceptionHandler("/Home/Error"); + #if (RequiresHttps) + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + } + + app.UseHttpsRedirection(); + #else + } + #endif + app.UseStaticFiles(); + + app.UseRouting(); + + #if (OrganizationalAuth || IndividualAuth || WindowsAuth) + app.UseAuthentication(); + #endif + app.UseAuthorization(); + + app.MapControllerRoute( + name: "default", + pattern: "{controller=Home}/{action=Index}/{id?}"); + #if (OrganizationalAuth || IndividualAuth) + app.MapRazorPages(); + #endif + + app.Run(); + } +}
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/dotnetcli.host.json index 9b97a61820..79217f1680 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/dotnetcli.host.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/dotnetcli.host.json @@ -85,6 +85,10 @@ "DisableOpenAPI": { "longName": "no-openapi", "shortName": "" + }, + "UseProgramMain": { + "longName": "use-program-main", + "shortName": "" } }, "usageExamples": [ diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/ide.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/ide.host.json index a6042e22b9..6b45461ce4 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/ide.host.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/ide.host.json @@ -58,6 +58,10 @@ "invertBoolean": true, "isVisible": true, "defaultValue": true + }, + { + "id": "UseProgramMain", + "isVisible": true } ], "disableHttpsSymbol": "NoHttps" diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.cs.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.cs.json index ec9b27882c..f82adc667d 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.cs.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.cs.json @@ -31,6 +31,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg or --auth IndividualB2C is specified.", "symbols/DisableOpenAPI/description": "Disable OpenAPI (Swagger) support", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.de.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.de.json index ec9b27882c..f82adc667d 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.de.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.de.json @@ -31,6 +31,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg or --auth IndividualB2C is specified.", "symbols/DisableOpenAPI/description": "Disable OpenAPI (Swagger) support", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.en.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.en.json index ec9b27882c..34a1dd0167 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.en.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.en.json @@ -31,6 +31,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg or --auth IndividualB2C is specified.", "symbols/DisableOpenAPI/description": "Disable OpenAPI (Swagger) support", + "symbols/UseProgramMain/displayName": "Do not use top-level statements", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.es.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.es.json index ec9b27882c..f82adc667d 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.es.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.es.json @@ -31,6 +31,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg or --auth IndividualB2C is specified.", "symbols/DisableOpenAPI/description": "Disable OpenAPI (Swagger) support", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.fr.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.fr.json index ec9b27882c..f82adc667d 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.fr.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.fr.json @@ -31,6 +31,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg or --auth IndividualB2C is specified.", "symbols/DisableOpenAPI/description": "Disable OpenAPI (Swagger) support", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.it.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.it.json index ec9b27882c..f82adc667d 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.it.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.it.json @@ -31,6 +31,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg or --auth IndividualB2C is specified.", "symbols/DisableOpenAPI/description": "Disable OpenAPI (Swagger) support", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.ja.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.ja.json index ec9b27882c..f82adc667d 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.ja.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.ja.json @@ -31,6 +31,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg or --auth IndividualB2C is specified.", "symbols/DisableOpenAPI/description": "Disable OpenAPI (Swagger) support", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.ko.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.ko.json index ec9b27882c..f82adc667d 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.ko.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.ko.json @@ -31,6 +31,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg or --auth IndividualB2C is specified.", "symbols/DisableOpenAPI/description": "Disable OpenAPI (Swagger) support", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.pl.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.pl.json index ec9b27882c..f82adc667d 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.pl.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.pl.json @@ -31,6 +31,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg or --auth IndividualB2C is specified.", "symbols/DisableOpenAPI/description": "Disable OpenAPI (Swagger) support", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.pt-BR.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.pt-BR.json index ec9b27882c..f82adc667d 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.pt-BR.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.pt-BR.json @@ -31,6 +31,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg or --auth IndividualB2C is specified.", "symbols/DisableOpenAPI/description": "Disable OpenAPI (Swagger) support", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.ru.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.ru.json index ec9b27882c..f82adc667d 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.ru.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.ru.json @@ -31,6 +31,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg or --auth IndividualB2C is specified.", "symbols/DisableOpenAPI/description": "Disable OpenAPI (Swagger) support", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.tr.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.tr.json index ec9b27882c..f82adc667d 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.tr.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.tr.json @@ -31,6 +31,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg or --auth IndividualB2C is specified.", "symbols/DisableOpenAPI/description": "Disable OpenAPI (Swagger) support", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.zh-Hans.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.zh-Hans.json index ec9b27882c..f82adc667d 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.zh-Hans.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.zh-Hans.json @@ -31,6 +31,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg or --auth IndividualB2C is specified.", "symbols/DisableOpenAPI/description": "Disable OpenAPI (Swagger) support", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.zh-Hant.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.zh-Hant.json index ec9b27882c..f82adc667d 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.zh-Hant.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/localize/templatestrings.zh-Hant.json @@ -31,6 +31,8 @@ "symbols/CallsMicrosoftGraph/description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg is specified.", "symbols/CalledApiScopes/description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg or --auth IndividualB2C is specified.", "symbols/DisableOpenAPI/description": "Disable OpenAPI (Swagger) support", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/template.json index d3683b75eb..e153789e02 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/template.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/template.json @@ -38,6 +38,21 @@ ] }, { + "condition": "(!UseProgramMain)", + "exclude": [ + "Program.Main.cs" + ] + }, + { + "condition": "(UseProgramMain && !UseMinimalAPIs)", + "exclude": [ + "Program.cs" + ], + "rename": { + "Program.Main.cs": "Program.cs" + } + }, + { "condition": "(UseMinimalAPIs)", "exclude": [ "Controllers/WeatherForecastController.cs", @@ -364,6 +379,13 @@ "UseControllers": { "type": "computed", "value": "(!UseMinimalAPIs)" + }, + "UseProgramMain": { + "type": "parameter", + "datatype": "bool", + "defaultValue": "false", + "displayName": "Do not use top-level statements", + "description": "Whether to generate an explicit Program class and Main method instead of top-level statements." } }, "primaryOutputs": [ diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.Main.cs new file mode 100644 index 0000000000..a0c9ad67e8 --- /dev/null +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.Main.cs @@ -0,0 +1,95 @@ +#if (OrganizationalAuth || IndividualB2CAuth) +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.JwtBearer; +#endif +#if (WindowsAuth) +using Microsoft.AspNetCore.Authentication.Negotiate; +#endif +#if (GenerateGraph) +using Graph = Microsoft.Graph; +#endif +#if (OrganizationalAuth || IndividualB2CAuth) +using Microsoft.Identity.Web; +#endif +#if (OrganizationalAuth || IndividualB2CAuth || GenerateGraph || WindowsAuth) + +#endif +namespace Company.WebApplication1; + +public class Program +{ + public static void Main(string[] args) + { + var builder = WebApplication.CreateBuilder(args); + + // Add services to the container. + #if (OrganizationalAuth) + builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) + #if (GenerateApiOrGraph) + .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd")) + .EnableTokenAcquisitionToCallDownstreamApi() + #if (GenerateApi) + .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi")) + #endif + #if (GenerateGraph) + .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi")) + #endif + .AddInMemoryTokenCaches(); + #else + .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd")); + #endif + #elif (IndividualB2CAuth) + builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) + #if (GenerateApi) + .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAdB2C")) + .EnableTokenAcquisitionToCallDownstreamApi() + .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi")) + .AddInMemoryTokenCaches(); + #else + .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAdB2C")); + #endif + #endif + + builder.Services.AddControllers(); + #if (EnableOpenAPI) + // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle + builder.Services.AddEndpointsApiExplorer(); + builder.Services.AddSwaggerGen(); + #endif + #if (WindowsAuth) + + builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme) + .AddNegotiate(); + + builder.Services.AddAuthorization(options => + { + // By default, all incoming requests will be authorized according to the default policy. + options.FallbackPolicy = options.DefaultPolicy; + }); + #endif + + var app = builder.Build(); + + // Configure the HTTP request pipeline. + #if (EnableOpenAPI) + if (app.Environment.IsDevelopment()) + { + app.UseSwagger(); + app.UseSwaggerUI(); + } + #endif + #if (RequiresHttps) + + app.UseHttpsRedirection(); + #endif + + #if (OrganizationalAuth || IndividualAuth || WindowsAuth) + app.UseAuthentication(); + #endif + app.UseAuthorization(); + + app.MapControllers(); + + app.Run(); + } +} diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/dotnetcli.host.json index b1cf98e39b..36493a3a4a 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/dotnetcli.host.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/dotnetcli.host.json @@ -11,6 +11,10 @@ "ExcludeLaunchSettings": { "longName": "exclude-launch-settings", "shortName": "" + }, + "UseProgramMain": { + "longName": "use-program-main", + "shortName": "" } }, "usageExamples": [ diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/ide.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/ide.host.json index 13a025d034..59f260a583 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/ide.host.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/ide.host.json @@ -3,4 +3,10 @@ "order": 300, "icon": "ide/Worker.png", "supportsDocker": true, + "symbolInfo": [ + { + "id": "UseProgramMain", + "isVisible": true + } + ] } diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.cs.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.cs.json index 018f87d2e8..23507879a5 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.cs.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.cs.json @@ -6,6 +6,8 @@ "symbols/Framework/description": "The target framework for the project.", "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.de.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.de.json index 018f87d2e8..23507879a5 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.de.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.de.json @@ -6,6 +6,8 @@ "symbols/Framework/description": "The target framework for the project.", "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.en.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.en.json index 018f87d2e8..859e306470 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.en.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.en.json @@ -6,6 +6,8 @@ "symbols/Framework/description": "The target framework for the project.", "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Do not use top-level statements", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.es.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.es.json index 018f87d2e8..23507879a5 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.es.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.es.json @@ -6,6 +6,8 @@ "symbols/Framework/description": "The target framework for the project.", "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.fr.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.fr.json index 018f87d2e8..23507879a5 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.fr.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.fr.json @@ -6,6 +6,8 @@ "symbols/Framework/description": "The target framework for the project.", "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.it.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.it.json index 018f87d2e8..23507879a5 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.it.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.it.json @@ -6,6 +6,8 @@ "symbols/Framework/description": "The target framework for the project.", "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.ja.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.ja.json index 018f87d2e8..23507879a5 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.ja.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.ja.json @@ -6,6 +6,8 @@ "symbols/Framework/description": "The target framework for the project.", "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.ko.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.ko.json index 018f87d2e8..23507879a5 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.ko.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.ko.json @@ -6,6 +6,8 @@ "symbols/Framework/description": "The target framework for the project.", "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.pl.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.pl.json index 018f87d2e8..23507879a5 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.pl.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.pl.json @@ -6,6 +6,8 @@ "symbols/Framework/description": "The target framework for the project.", "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.pt-BR.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.pt-BR.json index 018f87d2e8..23507879a5 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.pt-BR.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.pt-BR.json @@ -6,6 +6,8 @@ "symbols/Framework/description": "The target framework for the project.", "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.ru.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.ru.json index 018f87d2e8..23507879a5 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.ru.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.ru.json @@ -6,6 +6,8 @@ "symbols/Framework/description": "The target framework for the project.", "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.tr.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.tr.json index 018f87d2e8..23507879a5 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.tr.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.tr.json @@ -6,6 +6,8 @@ "symbols/Framework/description": "The target framework for the project.", "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.zh-Hans.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.zh-Hans.json index 018f87d2e8..23507879a5 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.zh-Hans.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.zh-Hans.json @@ -6,6 +6,8 @@ "symbols/Framework/description": "The target framework for the project.", "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.zh-Hant.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.zh-Hant.json index 018f87d2e8..23507879a5 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.zh-Hant.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/localize/templatestrings.zh-Hant.json @@ -6,6 +6,8 @@ "symbols/Framework/description": "The target framework for the project.", "symbols/Framework/choices/net7.0/description": "Target net7.0", "symbols/skipRestore/description": "If specified, skips the automatic restore of the project on create.", + "symbols/UseProgramMain/displayName": "Use a Program class with a Main method", + "symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.", "postActions/restore/description": "Restore NuGet packages required by this project.", "postActions/restore/manualInstructions/default/text": "Run 'dotnet restore'" }
\ No newline at end of file diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/template.json index 6fbdd3e798..5246a00539 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/template.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/template.json @@ -30,6 +30,21 @@ "exclude": [ "Properties/launchSettings.json" ] + }, + { + "condition": "(!UseProgramMain)", + "exclude": [ + "Program.Main.cs" + ] + }, + { + "condition": "(UseProgramMain)", + "exclude": [ + "Program.cs" + ], + "rename": { + "Program.Main.cs": "Program.cs" + } } ] } @@ -67,6 +82,13 @@ "datatype": "bool", "description": "If specified, skips the automatic restore of the project on create.", "defaultValue": "false" + }, + "UseProgramMain": { + "type": "parameter", + "datatype": "bool", + "defaultValue": "false", + "displayName": "Do not use top-level statements", + "description": "Whether to generate an explicit Program class and Main method instead of top-level statements." } }, "primaryOutputs": [ diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/Program.Main.cs new file mode 100644 index 0000000000..d69747f38d --- /dev/null +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/Program.Main.cs @@ -0,0 +1,18 @@ +using Company.Application1; + +namespace Company.WebApplication1; + +public class Program +{ + public static void Main(string[] args) + { + IHost host = Host.CreateDefaultBuilder(args) + .ConfigureServices(services => + { + services.AddHostedService<Worker>(); + }) + .Build(); + + host.Run(); + } +}
\ No newline at end of file diff --git a/src/ProjectTemplates/scripts/Run-Angular-Locally.ps1 b/src/ProjectTemplates/scripts/Run-Angular-Locally.ps1 index 95de6568ea..606071f061 100644 --- a/src/ProjectTemplates/scripts/Run-Angular-Locally.ps1 +++ b/src/ProjectTemplates/scripts/Run-Angular-Locally.ps1 @@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop' . $PSScriptRoot\Test-Template.ps1 -Test-Template "angular" "angular" "Microsoft.DotNet.Web.Spa.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false +Test-Template "angular" "angular" "Microsoft.DotNet.Web.Spa.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false diff --git a/src/ProjectTemplates/scripts/Run-AngularProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-AngularProgramMain-Locally.ps1 new file mode 100644 index 0000000000..955b9450ba --- /dev/null +++ b/src/ProjectTemplates/scripts/Run-AngularProgramMain-Locally.ps1 @@ -0,0 +1,12 @@ +#!/usr/bin/env pwsh +#requires -version 4 + +[CmdletBinding(PositionalBinding = $false)] +param() + +Set-StrictMode -Version 2 +$ErrorActionPreference = 'Stop' + +. $PSScriptRoot\Test-Template.ps1 + +Test-Template "angular" "angular --use-program-main" "Microsoft.DotNet.Web.Spa.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false diff --git a/src/ProjectTemplates/scripts/Run-Blazor-Locally.ps1 b/src/ProjectTemplates/scripts/Run-Blazor-Locally.ps1 index 7a510a7a9a..22b9f6db96 100644 --- a/src/ProjectTemplates/scripts/Run-Blazor-Locally.ps1 +++ b/src/ProjectTemplates/scripts/Run-Blazor-Locally.ps1 @@ -10,4 +10,4 @@ $ErrorActionPreference = 'Stop' . $PSScriptRoot\Test-Template.ps1 -Test-Template "blazorserver" "blazorserver" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false +Test-Template "blazorserver" "blazorserver" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false diff --git a/src/ProjectTemplates/scripts/Run-BlazorProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-BlazorProgramMain-Locally.ps1 new file mode 100644 index 0000000000..a5f89a1201 --- /dev/null +++ b/src/ProjectTemplates/scripts/Run-BlazorProgramMain-Locally.ps1 @@ -0,0 +1,13 @@ +#!/usr/bin/env pwsh +#requires -version 4 + +# This script packages, installs and creates a template to help with rapid iteration in the templating area. +[CmdletBinding(PositionalBinding = $false)] +param() + +Set-StrictMode -Version 2 +$ErrorActionPreference = 'Stop' + +. $PSScriptRoot\Test-Template.ps1 + +Test-Template "blazorserver" "blazorserver --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false diff --git a/src/ProjectTemplates/scripts/Run-BlazorWasm-Locally.ps1 b/src/ProjectTemplates/scripts/Run-BlazorWasm-Locally.ps1 index 50f70bb1b0..184f3c28f8 100644 --- a/src/ProjectTemplates/scripts/Run-BlazorWasm-Locally.ps1 +++ b/src/ProjectTemplates/scripts/Run-BlazorWasm-Locally.ps1 @@ -10,4 +10,4 @@ $ErrorActionPreference = 'Stop' . $PSScriptRoot\Test-Template.ps1 -Test-Template "blazorwasm" "blazorwasm --hosted --auth Individual" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $true +Test-Template "blazorwasm" "blazorwasm --hosted --auth Individual" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $true diff --git a/src/ProjectTemplates/scripts/Run-BlazorWasmProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-BlazorWasmProgramMain-Locally.ps1 new file mode 100644 index 0000000000..4c28a98793 --- /dev/null +++ b/src/ProjectTemplates/scripts/Run-BlazorWasmProgramMain-Locally.ps1 @@ -0,0 +1,13 @@ +#!/usr/bin/env pwsh +#requires -version 4 + +# This script packages, installs and creates a template to help with rapid iteration in the templating area. +[CmdletBinding(PositionalBinding = $false)] +param() + +Set-StrictMode -Version 2 +$ErrorActionPreference = 'Stop' + +. $PSScriptRoot\Test-Template.ps1 + +Test-Template "blazorwasm" "blazorwasm --use-program-main --hosted --auth Individual" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $true diff --git a/src/ProjectTemplates/scripts/Run-EmptyWeb-Locally.ps1 b/src/ProjectTemplates/scripts/Run-EmptyWeb-Locally.ps1 index 10e743504b..9d55079bf9 100644 --- a/src/ProjectTemplates/scripts/Run-EmptyWeb-Locally.ps1 +++ b/src/ProjectTemplates/scripts/Run-EmptyWeb-Locally.ps1 @@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop' . $PSScriptRoot\Test-Template.ps1 -Test-Template "web" "web" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false +Test-Template "web" "web" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false diff --git a/src/ProjectTemplates/scripts/Run-EmptyWebProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-EmptyWebProgramMain-Locally.ps1 new file mode 100644 index 0000000000..4fd0f95af0 --- /dev/null +++ b/src/ProjectTemplates/scripts/Run-EmptyWebProgramMain-Locally.ps1 @@ -0,0 +1,12 @@ +#!/usr/bin/env pwsh +#requires -version 4 + +[CmdletBinding(PositionalBinding = $false)] +param() + +Set-StrictMode -Version 2 +$ErrorActionPreference = 'Stop' + +. $PSScriptRoot\Test-Template.ps1 + +Test-Template "web" "web --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false diff --git a/src/ProjectTemplates/scripts/Run-Razor-Locally.ps1 b/src/ProjectTemplates/scripts/Run-Razor-Locally.ps1 index 6f16590be8..9dfe0c2178 100644 --- a/src/ProjectTemplates/scripts/Run-Razor-Locally.ps1 +++ b/src/ProjectTemplates/scripts/Run-Razor-Locally.ps1 @@ -6,4 +6,4 @@ param() . $PSScriptRoot\Test-Template.ps1 -Test-Template "webapp" "webapp -au Individual" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false +Test-Template "webapp" "webapp -au Individual" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false diff --git a/src/ProjectTemplates/scripts/Run-RazorProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-RazorProgramMain-Locally.ps1 new file mode 100644 index 0000000000..ada9e210b6 --- /dev/null +++ b/src/ProjectTemplates/scripts/Run-RazorProgramMain-Locally.ps1 @@ -0,0 +1,9 @@ +#!/usr/bin/env powershell +#requires -version 4 + +[CmdletBinding(PositionalBinding = $false)] +param() + +. $PSScriptRoot\Test-Template.ps1 + +Test-Template "webapp" "webapp -au Individual --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false diff --git a/src/ProjectTemplates/scripts/Run-React-Locally.ps1 b/src/ProjectTemplates/scripts/Run-React-Locally.ps1 index a4baf0c405..5be4be7ff5 100644 --- a/src/ProjectTemplates/scripts/Run-React-Locally.ps1 +++ b/src/ProjectTemplates/scripts/Run-React-Locally.ps1 @@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop' . $PSScriptRoot\Test-Template.ps1 -Test-Template "react" "react" "Microsoft.DotNet.Web.Spa.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false +Test-Template "react" "react" "Microsoft.DotNet.Web.Spa.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false diff --git a/src/ProjectTemplates/scripts/Run-ReactProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-ReactProgramMain-Locally.ps1 new file mode 100644 index 0000000000..ef8cc77d32 --- /dev/null +++ b/src/ProjectTemplates/scripts/Run-ReactProgramMain-Locally.ps1 @@ -0,0 +1,12 @@ +#!/usr/bin/env pwsh +#requires -version 4 + +[CmdletBinding(PositionalBinding = $false)] +param() + +Set-StrictMode -Version 2 +$ErrorActionPreference = 'Stop' + +. $PSScriptRoot\Test-Template.ps1 + +Test-Template "react" "react --use-program-main" "Microsoft.DotNet.Web.Spa.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false diff --git a/src/ProjectTemplates/scripts/Run-ReactRedux-Locally.ps1 b/src/ProjectTemplates/scripts/Run-ReactRedux-Locally.ps1 index aedd8ec88a..06303a076a 100644 --- a/src/ProjectTemplates/scripts/Run-ReactRedux-Locally.ps1 +++ b/src/ProjectTemplates/scripts/Run-ReactRedux-Locally.ps1 @@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop' . $PSScriptRoot\Test-Template.ps1 -Test-Template "reactredux" "reactredux" "Microsoft.DotNet.Web.Spa.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false +Test-Template "reactredux" "reactredux" "Microsoft.DotNet.Web.Spa.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false diff --git a/src/ProjectTemplates/scripts/Run-Starterweb-Locally.ps1 b/src/ProjectTemplates/scripts/Run-Starterweb-Locally.ps1 index ab195cd016..c411befc5a 100644 --- a/src/ProjectTemplates/scripts/Run-Starterweb-Locally.ps1 +++ b/src/ProjectTemplates/scripts/Run-Starterweb-Locally.ps1 @@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop' . $PSScriptRoot\Test-Template.ps1 -Test-Template "mvc" "mvc -au Individual" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false +Test-Template "mvc" "mvc -au Individual" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false diff --git a/src/ProjectTemplates/scripts/Run-StarterwebProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-StarterwebProgramMain-Locally.ps1 new file mode 100644 index 0000000000..d262c5eb50 --- /dev/null +++ b/src/ProjectTemplates/scripts/Run-StarterwebProgramMain-Locally.ps1 @@ -0,0 +1,12 @@ +#!/usr/bin/env pwsh +#requires -version 4 + +[CmdletBinding(PositionalBinding = $false)] +param() + +Set-StrictMode -Version 2 +$ErrorActionPreference = 'Stop' + +. $PSScriptRoot\Test-Template.ps1 + +Test-Template "mvc" "mvc -au Individual --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false diff --git a/src/ProjectTemplates/scripts/Run-WebApi-Locally.ps1 b/src/ProjectTemplates/scripts/Run-WebApi-Locally.ps1 index 467d6e57e7..14f003acfd 100644 --- a/src/ProjectTemplates/scripts/Run-WebApi-Locally.ps1 +++ b/src/ProjectTemplates/scripts/Run-WebApi-Locally.ps1 @@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop' . $PSScriptRoot\Test-Template.ps1 -Test-Template "webapi" "webapi" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false +Test-Template "webapi" "webapi" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false diff --git a/src/ProjectTemplates/scripts/Run-WebApiMinimal-Locally.ps1 b/src/ProjectTemplates/scripts/Run-WebApiMinimal-Locally.ps1 index 19325a7c7e..4e32b826f8 100644 --- a/src/ProjectTemplates/scripts/Run-WebApiMinimal-Locally.ps1 +++ b/src/ProjectTemplates/scripts/Run-WebApiMinimal-Locally.ps1 @@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop' . $PSScriptRoot\Test-Template.ps1 -Test-Template "webapimin" "webapi -minimal" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false +Test-Template "webapimin" "webapi -minimal" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false diff --git a/src/ProjectTemplates/scripts/Run-WebApiProgamMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-WebApiProgamMain-Locally.ps1 new file mode 100644 index 0000000000..dafce77763 --- /dev/null +++ b/src/ProjectTemplates/scripts/Run-WebApiProgamMain-Locally.ps1 @@ -0,0 +1,12 @@ +#!/usr/bin/env pwsh +#requires -version 4 + +[CmdletBinding(PositionalBinding = $false)] +param() + +Set-StrictMode -Version 2 +$ErrorActionPreference = 'Stop' + +. $PSScriptRoot\Test-Template.ps1 + +Test-Template "webapi" "webapi --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false diff --git a/src/ProjectTemplates/scripts/Run-Worker-Locally.ps1 b/src/ProjectTemplates/scripts/Run-Worker-Locally.ps1 index 9f3c027209..7ccf87d528 100644 --- a/src/ProjectTemplates/scripts/Run-Worker-Locally.ps1 +++ b/src/ProjectTemplates/scripts/Run-Worker-Locally.ps1 @@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop' . $PSScriptRoot\Test-Template.ps1 -Test-Template "worker" "worker" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false +Test-Template "worker" "worker" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false diff --git a/src/ProjectTemplates/scripts/Run-WorkerProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-WorkerProgramMain-Locally.ps1 new file mode 100644 index 0000000000..42b013ef27 --- /dev/null +++ b/src/ProjectTemplates/scripts/Run-WorkerProgramMain-Locally.ps1 @@ -0,0 +1,12 @@ +#!/usr/bin/env pwsh +#requires -version 4 + +[CmdletBinding(PositionalBinding = $false)] +param() + +Set-StrictMode -Version 2 +$ErrorActionPreference = 'Stop' + +. $PSScriptRoot\Test-Template.ps1 + +Test-Template "worker" "worker --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false diff --git a/src/ProjectTemplates/scripts/Run-gRPC-Locally.ps1 b/src/ProjectTemplates/scripts/Run-gRPC-Locally.ps1 index 2803a34d9c..d201cda047 100644 --- a/src/ProjectTemplates/scripts/Run-gRPC-Locally.ps1 +++ b/src/ProjectTemplates/scripts/Run-gRPC-Locally.ps1 @@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop' . $PSScriptRoot\Test-Template.ps1 -Test-Template "grpc" "grpc" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false +Test-Template "grpc" "grpc" "Microsoft.DotNet.Web.ProjectTemplates.7.0.7.0.0-dev.nupkg" $false diff --git a/src/ProjectTemplates/scripts/Test-Template.ps1 b/src/ProjectTemplates/scripts/Test-Template.ps1 index 242558493d..1774b47735 100644 --- a/src/ProjectTemplates/scripts/Test-Template.ps1 +++ b/src/ProjectTemplates/scripts/Test-Template.ps1 @@ -64,7 +64,9 @@ function Test-Template($templateName, $templateArgs, $templateNupkg, $isBlazorWa if ($isBlazorWasmHosted) { Push-Location Server } - dotnet.exe ef migrations add mvc + if ($templateArgs -match '-au') { + dotnet.exe ef migrations add mvc + } dotnet.exe publish --configuration Release Set-Location .\bin\Release\net7.0\publish if ($isBlazorWasm -eq $false) { diff --git a/src/ProjectTemplates/test/BlazorServerTemplateTest.cs b/src/ProjectTemplates/test/BlazorServerTemplateTest.cs index b10647182a..92120b20fb 100644 --- a/src/ProjectTemplates/test/BlazorServerTemplateTest.cs +++ b/src/ProjectTemplates/test/BlazorServerTemplateTest.cs @@ -26,18 +26,26 @@ public class BlazorServerTemplateTest : BlazorTemplateTest [Fact] public Task BlazorServerTemplateWorks_NoAuth() => CreateBuildPublishAsync("blazorservernoauth"); + [Fact] + public Task BlazorServerTemplateWorks_ProgamMainNoAuth() => CreateBuildPublishAsync("blazorservernoauth", args: new [] { "--use-program-main" }); + [Theory] - [InlineData(true)] - [InlineData(false)] + [InlineData(true, null)] + [InlineData(true, new string[] { "--use-program-main" })] + [InlineData(false, null)] + [InlineData(false, new string[] { "--use-program-main" })] [SkipOnHelix("https://github.com/dotnet/aspnetcore/issues/30825", Queues = "All.OSX")] - public Task BlazorServerTemplateWorks_IndividualAuth(bool useLocalDB) => CreateBuildPublishAsync("blazorserverindividual" + (useLocalDB ? "uld" : "")); + public Task BlazorServerTemplateWorks_IndividualAuth(bool useLocalDB, string[] args) => CreateBuildPublishAsync("blazorserverindividual" + (useLocalDB ? "uld" : "", args: args)); [Theory] [InlineData("IndividualB2C", null)] [InlineData("IndividualB2C", new string[] { "--called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })] + [InlineData("IndividualB2C", new string[] { "--use-program-main", "--called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })] [InlineData("SingleOrg", null)] [InlineData("SingleOrg", new string[] { "--called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })] + [InlineData("SingleOrg", new string[] { "--use-program-main --called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })] [InlineData("SingleOrg", new string[] { "--calls-graph" })] + [InlineData("SingleOrg", new string[] { "--use-program-main --calls-graph" })] public Task BlazorServerTemplate_IdentityWeb_BuildAndPublish(string auth, string[] args) => CreateBuildPublishAsync("blazorserveridweb" + Guid.NewGuid().ToString().Substring(0, 10).ToLowerInvariant(), auth, args); diff --git a/src/ProjectTemplates/test/BlazorWasmTemplateTest.cs b/src/ProjectTemplates/test/BlazorWasmTemplateTest.cs index 223c0259eb..aad7638674 100644 --- a/src/ProjectTemplates/test/BlazorWasmTemplateTest.cs +++ b/src/ProjectTemplates/test/BlazorWasmTemplateTest.cs @@ -38,6 +38,9 @@ public class BlazorWasmTemplateTest : BlazorTemplateTest public Task BlazorWasmHostedTemplateCanCreateBuildPublish() => CreateBuildPublishAsync("blazorhosted", args: new[] { "--hosted" }, serverProject: true); [Fact] + public Task BlazorWasmHostedTemplateWithProgamMainCanCreateBuildPublish() => CreateBuildPublishAsync("blazorhosted", args: new[] { "--use-program-main", "--hosted" }, serverProject: true); + + [Fact] public Task BlazorWasmStandalonePwaTemplateCanCreateBuildPublish() => CreateBuildPublishAsync("blazorstandalonepwa", args: new[] { "--pwa" }); [Fact] diff --git a/src/ProjectTemplates/test/EmptyWebTemplateTest.cs b/src/ProjectTemplates/test/EmptyWebTemplateTest.cs index b37648b65a..addfd26c81 100644 --- a/src/ProjectTemplates/test/EmptyWebTemplateTest.cs +++ b/src/ProjectTemplates/test/EmptyWebTemplateTest.cs @@ -38,17 +38,24 @@ public class EmptyWebTemplateTest : LoggedTest await EmtpyTemplateCore(languageOverride: null); } + [ConditionalFact] + [SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)] + public async Task EmptyWebTemplateProgramMainCSharp() + { + await EmtpyTemplateCore(languageOverride: null, args: new [] { "--use-program-main" }); + } + [Fact] public async Task EmptyWebTemplateFSharp() { await EmtpyTemplateCore("F#"); } - private async Task EmtpyTemplateCore(string languageOverride) + private async Task EmtpyTemplateCore(string languageOverride, string[] args = null) { var project = await ProjectFactory.GetOrCreateProject("empty" + (languageOverride == "F#" ? "fsharp" : "csharp"), Output); - var createResult = await project.RunDotNetNewAsync("web", language: languageOverride); + var createResult = await project.RunDotNetNewAsync("web", args: args, language: languageOverride); Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult)); // Avoid the F# compiler. See https://github.com/dotnet/aspnetcore/issues/14022 diff --git a/src/ProjectTemplates/test/GrpcTemplateTest.cs b/src/ProjectTemplates/test/GrpcTemplateTest.cs index 5a94bfc9f0..e7cbf12621 100644 --- a/src/ProjectTemplates/test/GrpcTemplateTest.cs +++ b/src/ProjectTemplates/test/GrpcTemplateTest.cs @@ -34,14 +34,17 @@ public class GrpcTemplateTest : LoggedTest } } - [ConditionalFact] + [ConditionalTheory] [SkipOnHelix("Not supported queues", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)] [SkipOnAlpine("https://github.com/grpc/grpc/issues/18338")] - public async Task GrpcTemplate() + [InlineData(true)] + [InlineData(false)] + public async Task GrpcTemplate(bool useProgramMain) { var project = await ProjectFactory.GetOrCreateProject("grpc", Output); - var createResult = await project.RunDotNetNewAsync("grpc"); + var args = useProgramMain ? new [] { "--use-program-main" } : null; + var createResult = await project.RunDotNetNewAsync("grpc", args: args); Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult)); var publishResult = await project.RunDotNetPublishAsync(); diff --git a/src/ProjectTemplates/test/MvcTemplateTest.cs b/src/ProjectTemplates/test/MvcTemplateTest.cs index 5ccdf8e675..340e13b58c 100644 --- a/src/ProjectTemplates/test/MvcTemplateTest.cs +++ b/src/ProjectTemplates/test/MvcTemplateTest.cs @@ -36,11 +36,15 @@ public class MvcTemplateTest : LoggedTest [SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)] public async Task MvcTemplate_NoAuthCSharp() => await MvcTemplateCore(languageOverride: null); - private async Task MvcTemplateCore(string languageOverride) + [ConditionalFact] + [SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)] + public async Task MvcTemplate_ProgramMainNoAuthCSharp() => await MvcTemplateCore(languageOverride: null, new [] { "--use-program-main" }); + + private async Task MvcTemplateCore(string languageOverride, string[] args = null) { var project = await ProjectFactory.GetOrCreateProject("mvcnoauth" + (languageOverride == "F#" ? "fsharp" : "csharp"), Output); - var createResult = await project.RunDotNetNewAsync("mvc", language: languageOverride); + var createResult = await project.RunDotNetNewAsync("mvc", language: languageOverride, args: args); Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult)); var projectExtension = languageOverride == "F#" ? "fsproj" : "csproj"; @@ -109,14 +113,17 @@ public class MvcTemplateTest : LoggedTest } [ConditionalTheory] - [InlineData(true)] - [InlineData(false)] + [InlineData(true, false)] + [InlineData(true, true)] + [InlineData(false, false)] + [InlineData(false, true)] [SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)] - public async Task MvcTemplate_IndividualAuth(bool useLocalDB) + public async Task MvcTemplate_IndividualAuth(bool useLocalDB, bool useProgramMain) { var project = await ProjectFactory.GetOrCreateProject("mvcindividual" + (useLocalDB ? "uld" : ""), Output); - var createResult = await project.RunDotNetNewAsync("mvc", auth: "Individual", useLocalDB: useLocalDB); + var args = useProgramMain ? new [] { "--use-program-main" } : null; + var createResult = await project.RunDotNetNewAsync("mvc", auth: "Individual", useLocalDB: useLocalDB, args: args); Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult)); var projectFileContents = project.ReadFile($"{project.ProjectName}.csproj"); diff --git a/src/ProjectTemplates/test/RazorPagesTemplateTest.cs b/src/ProjectTemplates/test/RazorPagesTemplateTest.cs index 4534c66426..c56cc9762a 100644 --- a/src/ProjectTemplates/test/RazorPagesTemplateTest.cs +++ b/src/ProjectTemplates/test/RazorPagesTemplateTest.cs @@ -34,13 +34,16 @@ public class RazorPagesTemplateTest : LoggedTest } } - [ConditionalFact] + [ConditionalTheory] [SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)] - public async Task RazorPagesTemplate_NoAuth() + [InlineData(true)] + [InlineData(false)] + public async Task RazorPagesTemplate_NoAuth(bool useProgramMain) { var project = await ProjectFactory.GetOrCreateProject("razorpagesnoauth", Output); - var createResult = await project.RunDotNetNewAsync("razor"); + var args = useProgramMain ? new [] { "--use-program-main" } : null; + var createResult = await project.RunDotNetNewAsync("razor", args: args); Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("razor", project, createResult)); var projectFileContents = ReadFile(project.TemplateOutputDir, $"{project.ProjectName}.csproj"); @@ -104,14 +107,17 @@ public class RazorPagesTemplateTest : LoggedTest } [ConditionalTheory] - [InlineData(false)] - [InlineData(true)] + [InlineData(false, false)] + [InlineData(false, true)] + [InlineData(true, false)] + [InlineData(true, true)] [SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)] - public async Task RazorPagesTemplate_IndividualAuth(bool useLocalDB) + public async Task RazorPagesTemplate_IndividualAuth(bool useLocalDB, bool useProgramMain) { var project = await ProjectFactory.GetOrCreateProject("razorpagesindividual" + (useLocalDB ? "uld" : ""), Output); - var createResult = await project.RunDotNetNewAsync("razor", auth: "Individual", useLocalDB: useLocalDB); + var args = useProgramMain ? new [] { "--use-program-main" } : null; + var createResult = await project.RunDotNetNewAsync("razor", auth: "Individual", useLocalDB: useLocalDB, args: args); Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult)); var projectFileContents = ReadFile(project.TemplateOutputDir, $"{project.ProjectName}.csproj"); @@ -226,12 +232,15 @@ public class RazorPagesTemplateTest : LoggedTest [SkipOnHelix("https://github.com/dotnet/aspnetcore/issues/28090", Queues = HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)] [InlineData("IndividualB2C", null)] [InlineData("IndividualB2C", new string[] { "--called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })] + [InlineData("IndividualB2C", new string[] { "--use-program-main --called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })] [InlineData("SingleOrg", null)] [InlineData("SingleOrg", new string[] { "--called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })] + [InlineData("SingleOrg", new string[] { "--use-program-main --called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })] public Task RazorPagesTemplate_IdentityWeb_BuildsAndPublishes(string auth, string[] args) => BuildAndPublishRazorPagesTemplate(auth: auth, args: args); [ConditionalTheory] [InlineData("SingleOrg", new string[] { "--calls-graph" })] + [InlineData("SingleOrg", new string[] { "--use-program-main --calls-graph" })] public Task RazorPagesTemplate_IdentityWeb_BuildsAndPublishes_WithSingleOrg(string auth, string[] args) => BuildAndPublishRazorPagesTemplate(auth: auth, args: args); private async Task<Project> BuildAndPublishRazorPagesTemplate(string auth, string[] args) diff --git a/src/ProjectTemplates/test/WebApiTemplateTest.cs b/src/ProjectTemplates/test/WebApiTemplateTest.cs index 6d3889bce6..76425a7257 100644 --- a/src/ProjectTemplates/test/WebApiTemplateTest.cs +++ b/src/ProjectTemplates/test/WebApiTemplateTest.cs @@ -35,10 +35,15 @@ public class WebApiTemplateTest : LoggedTest [ConditionalTheory] [SkipOnHelix("https://github.com/dotnet/aspnetcore/issues/28090", Queues = HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)] [InlineData("IndividualB2C", null)] + [InlineData("IndividualB2C", new string[] { "--use-program-main" })] [InlineData("IndividualB2C", new string[] { "--called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })] + [InlineData("IndividualB2C", new string[] { "--use-program-main --called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })] [InlineData("SingleOrg", null)] + [InlineData("SingleOrg", new string[] { "--use-program-main" })] [InlineData("SingleOrg", new string[] { "--called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })] + [InlineData("SingleOrg", new string[] { "--use-program-main --called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })] [InlineData("SingleOrg", new string[] { "--calls-graph" })] + [InlineData("SingleOrg", new string[] { "--use-program-main --calls-graph" })] public Task WebApiTemplateCSharp_IdentityWeb_BuildsAndPublishes(string auth, string[] args) => PublishAndBuildWebApiTemplate(languageOverride: null, auth: auth, args: args); [Fact] @@ -50,11 +55,18 @@ public class WebApiTemplateTest : LoggedTest [ConditionalFact] [SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)] - public async Task WebApiTemplateCSharp_WithoutOpenAPI() + public Task WebApiTemplateProgramMainCSharp() => WebApiTemplateCore(languageOverride: null, args: new [] { "--use-program-main" }); + + [ConditionalTheory] + [InlineData(false)] + [InlineData(true)] + [SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)] + public async Task WebApiTemplateCSharp_WithoutOpenAPI(bool useProgramMain) { var project = await FactoryFixture.GetOrCreateProject("webapinoopenapi", Output); - var createResult = await project.RunDotNetNewAsync("webapi", args: new[] { "--no-openapi" }); + var args = useProgramMain ? new[] { "--use-program-main --no-openapi" } : new[] { "--no-openapi" }; + var createResult = await project.RunDotNetNewAsync("webapi", args: args); Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult)); var buildResult = await project.RunDotNetBuildAsync(); @@ -68,7 +80,7 @@ public class WebApiTemplateTest : LoggedTest await aspNetProcess.AssertNotFound("swagger"); } - private async Task<Project> PublishAndBuildWebApiTemplate(string languageOverride, string auth, string[] args) + private async Task<Project> PublishAndBuildWebApiTemplate(string languageOverride, string auth, string[] args = null) { var project = await FactoryFixture.GetOrCreateProject("webapi" + (languageOverride == "F#" ? "fsharp" : "csharp") + Guid.NewGuid().ToString().Substring(0, 10).ToLowerInvariant(), Output); @@ -94,9 +106,9 @@ public class WebApiTemplateTest : LoggedTest return project; } - private async Task WebApiTemplateCore(string languageOverride) + private async Task WebApiTemplateCore(string languageOverride, string[] args = null) { - var project = await PublishAndBuildWebApiTemplate(languageOverride, null, null); + var project = await PublishAndBuildWebApiTemplate(languageOverride, null, args); // Avoid the F# compiler. See https://github.com/dotnet/aspnetcore/issues/14022 if (languageOverride != null) diff --git a/src/ProjectTemplates/test/WorkerTemplateTest.cs b/src/ProjectTemplates/test/WorkerTemplateTest.cs index c1d2e961a8..8af59b84fe 100644 --- a/src/ProjectTemplates/test/WorkerTemplateTest.cs +++ b/src/ProjectTemplates/test/WorkerTemplateTest.cs @@ -32,16 +32,17 @@ public class WorkerTemplateTest : LoggedTest [ConditionalTheory] [OSSkipCondition(OperatingSystems.Linux, SkipReason = "https://github.com/dotnet/sdk/issues/12831")] - [InlineData("C#")] - [InlineData("F#")] + [InlineData("C#", null)] + [InlineData("C#", new string[] { "--use-program-main" })] + [InlineData("F#", null)] [QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/25404")] - public async Task WorkerTemplateAsync(string language) + public async Task WorkerTemplateAsync(string language, string[] args) { var project = await ProjectFactory.GetOrCreateProject( $"worker-{ language.ToLowerInvariant()[0] }sharp", Output); - var createResult = await project.RunDotNetNewAsync("worker", language: language); + var createResult = await project.RunDotNetNewAsync("worker", language: language, args: args); Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult)); var publishResult = await project.RunDotNetPublishAsync(); diff --git a/src/Security/Authentication/Cookies/src/CookieAuthenticationEvents.cs b/src/Security/Authentication/Cookies/src/CookieAuthenticationEvents.cs index 613d9fab67..1b13746bb2 100644 --- a/src/Security/Authentication/Cookies/src/CookieAuthenticationEvents.cs +++ b/src/Security/Authentication/Cookies/src/CookieAuthenticationEvents.cs @@ -109,10 +109,16 @@ public class CookieAuthenticationEvents } /// <summary> - /// Invoked to validate the prinicipal. + /// Invoked to validate the principal. /// </summary> /// <param name="context">The <see cref="CookieValidatePrincipalContext"/>.</param> public virtual Task ValidatePrincipal(CookieValidatePrincipalContext context) => OnValidatePrincipal(context); + + /// <summary> + /// Invoked to check if the cookie should be renewed. + /// </summary> + /// <param name="context">The <see cref="CookieSlidingExpirationContext"/>.</param> + public virtual Task CheckSlidingExpiration(CookieSlidingExpirationContext context) => OnCheckSlidingExpiration(context); /// <summary> /// Invoked during sign in. diff --git a/src/Security/Authentication/Cookies/src/CookieAuthenticationHandler.cs b/src/Security/Authentication/Cookies/src/CookieAuthenticationHandler.cs index 8300d7fcaf..7cfa4f94bb 100644 --- a/src/Security/Authentication/Cookies/src/CookieAuthenticationHandler.cs +++ b/src/Security/Authentication/Cookies/src/CookieAuthenticationHandler.cs @@ -93,7 +93,7 @@ public class CookieAuthenticationHandler : SignInAuthenticationHandler<CookieAut { ShouldRenew = timeRemaining < timeElapsed, }; - await Options.Events.OnCheckSlidingExpiration(eventContext); + await Options.Events.CheckSlidingExpiration(eventContext); if (eventContext.ShouldRenew) { diff --git a/src/Security/Authentication/Cookies/src/PublicAPI.Unshipped.txt b/src/Security/Authentication/Cookies/src/PublicAPI.Unshipped.txt index 9ed3fc11d3..899d7d2843 100644 --- a/src/Security/Authentication/Cookies/src/PublicAPI.Unshipped.txt +++ b/src/Security/Authentication/Cookies/src/PublicAPI.Unshipped.txt @@ -1,3 +1,4 @@ #nullable enable *REMOVED*Microsoft.AspNetCore.Authentication.Cookies.PostConfigureCookieAuthenticationOptions.PostConfigure(string! name, Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions! options) -> void Microsoft.AspNetCore.Authentication.Cookies.PostConfigureCookieAuthenticationOptions.PostConfigure(string? name, Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions! options) -> void +virtual Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationEvents.CheckSlidingExpiration(Microsoft.AspNetCore.Authentication.Cookies.CookieSlidingExpirationContext! context) -> System.Threading.Tasks.Task! diff --git a/src/Security/Authentication/test/CertificateTests.cs b/src/Security/Authentication/test/CertificateTests.cs index f69360da79..03fd439a36 100644 --- a/src/Security/Authentication/test/CertificateTests.cs +++ b/src/Security/Authentication/test/CertificateTests.cs @@ -153,7 +153,7 @@ public class ClientCertificateAuthenticationTests } [ConditionalFact] - [SkipOnHelix("https://github.com/dotnet/aspnetcore/issues/32813", Queues = "All.Ubuntu")] + [SkipOnHelix("https://github.com/dotnet/aspnetcore/issues/32813", Queues = $"All.Ubuntu;{HelixConstants.RedhatAmd64}")] public async Task VerifyExpiredSelfSignedFails() { using var host = await CreateHost( @@ -188,7 +188,7 @@ public class ClientCertificateAuthenticationTests } [ConditionalFact] - [SkipOnHelix("https://github.com/dotnet/aspnetcore/issues/32813", Queues = "All.Ubuntu")] + [SkipOnHelix("https://github.com/dotnet/aspnetcore/issues/32813", Queues = $"All.Ubuntu;{HelixConstants.RedhatAmd64}")] public async Task VerifyNotYetValidSelfSignedFails() { using var host = await CreateHost( diff --git a/src/Servers/IIS/IIS/perf/Microbenchmarks/PlaintextBenchmark.cs b/src/Servers/IIS/IIS/perf/Microbenchmarks/PlaintextBenchmark.cs index ee38cb1588..a98b53326b 100644 --- a/src/Servers/IIS/IIS/perf/Microbenchmarks/PlaintextBenchmark.cs +++ b/src/Servers/IIS/IIS/perf/Microbenchmarks/PlaintextBenchmark.cs @@ -27,7 +27,8 @@ public class PlaintextBenchmark // Recreate client, TestServer.Client has additional logging that can hurt performance _client = new HttpClient() { - BaseAddress = _server.HttpClient.BaseAddress + BaseAddress = _server.HttpClient.BaseAddress, + Timeout = TimeSpan.FromSeconds(200), }; } diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/CompressionTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/CompressionTests.cs index cc8f46bbb9..20278b0aa1 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/CompressionTests.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/CompressionTests.cs @@ -130,6 +130,7 @@ public class CompressionTests : FixtureLoggedTest var client = new HttpClient(handler) { BaseAddress = _fixture.Client.BaseAddress, + Timeout = TimeSpan.FromSeconds(200), }; client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip")); client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("identity", 0)); diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/FrebTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/FrebTests.cs index 24cceea63a..ea01504eca 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/FrebTests.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/FrebTests.cs @@ -90,10 +90,7 @@ public class FrebTests : IISFunctionalTestBase AssertFrebLogs(result, new FrebLogItem("ANCM_INPROC_ASYNC_COMPLETION_COMPLETION", "2")); } - // I think this test is flaky due to freb file not being created quickly enough. - // Adding extra logging, marking as flaky, and repeating should help [ConditionalFact] - [Repeat(10)] [RequiresIIS(IISCapability.FailedRequestTracingModule)] public async Task CheckFrebDisconnect() { diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Http2Tests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Http2Tests.cs index e069cc2976..34906e32e4 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Http2Tests.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Http2Tests.cs @@ -356,7 +356,7 @@ public class Http2Tests { var handler = new HttpClientHandler(); handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator; - using HttpClient client = new HttpClient(handler); + using var client = new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(200) }; client.DefaultRequestVersion = HttpVersion.Version11; var response = await client.GetStringAsync(Fixture.Client.BaseAddress + "Reset_Http1_NotSupported"); Assert.Equal("Hello World", response); @@ -370,7 +370,7 @@ public class Http2Tests { var handler = new HttpClientHandler(); handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator; - using HttpClient client = new HttpClient(handler); + using var client = new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(200) }; client.DefaultRequestVersion = HttpVersion.Version20; var response = await client.GetStringAsync(Fixture.Client.BaseAddress + "Reset_PriorOSVersions_NotSupported"); Assert.Equal("Hello World", response); @@ -390,7 +390,7 @@ public class Http2Tests var handler = new HttpClientHandler(); handler.MaxResponseHeadersLength = 128; handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator; - using var client = new HttpClient(handler); + using var client = new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(200) }; client.DefaultRequestVersion = http2 ? HttpVersion.Version20 : HttpVersion.Version11; return await client.GetAsync(uri); } diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/EventLogHelpers.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/EventLogHelpers.cs index a6b41e9e07..2830ffaed2 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/EventLogHelpers.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/EventLogHelpers.cs @@ -88,7 +88,7 @@ public class EventLogHelpers var processIdString = $"Process Id: {deploymentResult.HostProcess.Id}."; // Event log messages round down to the nearest second, so subtract 5 seconds to make sure we get event logs - var processStartTime = deploymentResult.HostProcess.StartTime.AddSeconds(-5); + var processStartTime = deploymentResult.HostProcess.StartTime.AddSeconds(-10); for (var i = eventLog.Entries.Count - 1; i >= 0; i--) { var eventLogEntry = eventLog.Entries[i]; diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/Helpers.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/Helpers.cs index af3e945d1f..0b8c5bbeff 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/Helpers.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/Helpers.cs @@ -1,19 +1,14 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; -using System.Collections.Generic; using System.Diagnostics; -using System.IO; -using System.Linq; +using System.Net; using System.Net.Http; -using System.Threading.Tasks; using System.Xml.Linq; using Microsoft.AspNetCore.Server.IntegrationTesting; using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; using Microsoft.Extensions.Logging; using Newtonsoft.Json; -using Xunit; namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests; @@ -29,18 +24,28 @@ public static class Helpers public static async Task AssertStarts(this IISDeploymentResult deploymentResult, string path = "/HelloWorld") { - var response = await deploymentResult.HttpClient.GetAsync(path); - + // Sometimes the site is not ready, so retry until its actually started and ready + var response = await deploymentResult.HttpClient.RetryRequestAsync(path, r => r.IsSuccessStatusCode); var responseText = await response.Content.ReadAsStringAsync(); - - Assert.Equal("Hello World", responseText); + if (response.IsSuccessStatusCode) + { + Assert.Equal("Hello World", responseText); + } + else + { + throw new Exception($"Server not started successfully, recieved non success status code, responseText: {responseText}"); + } } public static async Task StressLoad(HttpClient httpClient, string path, Action<HttpResponseMessage> action) { async Task RunRequests() { - var connection = new HttpClient() { BaseAddress = httpClient.BaseAddress }; + var connection = new HttpClient() + { + BaseAddress = httpClient.BaseAddress, + Timeout = TimeSpan.FromSeconds(200), + }; for (int j = 0; j < 10; j++) { diff --git a/src/Servers/IIS/IIS/test/Common.LongTests/StartupTests.cs b/src/Servers/IIS/IIS/test/Common.LongTests/StartupTests.cs index b2599611d7..3ea9955b98 100644 --- a/src/Servers/IIS/IIS/test/Common.LongTests/StartupTests.cs +++ b/src/Servers/IIS/IIS/test/Common.LongTests/StartupTests.cs @@ -410,7 +410,7 @@ public class StartupTests : IISFunctionalTestBase Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); var responseContent = await response.Content.ReadAsStringAsync(); Assert.Contains("500.31", responseContent); - Assert.Contains("The framework 'Microsoft.NETCore.App', version '2.9.9'", responseContent); + Assert.Contains("Framework: 'Microsoft.NETCore.App', version '2.9.9'", responseContent); } else { @@ -1354,7 +1354,8 @@ public class StartupTests : IISFunctionalTestBase }; var client = new HttpClient(handler) { - BaseAddress = new Uri(deploymentParameters.ApplicationBaseUriHint) + BaseAddress = new Uri(deploymentParameters.ApplicationBaseUriHint), + Timeout = TimeSpan.FromSeconds(200), }; if (DeployerSelector.HasNewHandler) diff --git a/src/Servers/IIS/IIS/test/IIS.FunctionalTests/Http2TrailersResetTests.cs b/src/Servers/IIS/IIS/test/IIS.FunctionalTests/Http2TrailersResetTests.cs index 93d959b14a..d05619647b 100644 --- a/src/Servers/IIS/IIS/test/IIS.FunctionalTests/Http2TrailersResetTests.cs +++ b/src/Servers/IIS/IIS/test/IIS.FunctionalTests/Http2TrailersResetTests.cs @@ -503,7 +503,7 @@ public class Http2TrailerResetTests : FunctionalTestsBase var handler = new HttpClientHandler(); handler.MaxResponseHeadersLength = 128; handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator; - var client = new HttpClient(handler); + var client = new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(200) }; return client; } @@ -512,7 +512,7 @@ public class Http2TrailerResetTests : FunctionalTestsBase var handler = new HttpClientHandler(); handler.MaxResponseHeadersLength = 128; handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator; - using var client = new HttpClient(handler); + using var client = new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(200) }; client.DefaultRequestVersion = http2 ? HttpVersion.Version20 : HttpVersion.Version11; return await client.GetAsync(uri); } diff --git a/src/Servers/IIS/IIS/test/IIS.FunctionalTests/Http3Tests.cs b/src/Servers/IIS/IIS/test/IIS.FunctionalTests/Http3Tests.cs index 41f4fec311..be5022389b 100644 --- a/src/Servers/IIS/IIS/test/IIS.FunctionalTests/Http3Tests.cs +++ b/src/Servers/IIS/IIS/test/IIS.FunctionalTests/Http3Tests.cs @@ -173,6 +173,6 @@ public class Http3Tests : FunctionalTestsBase var handler = new HttpClientHandler(); // Needed on CI, the IIS Express cert we use isn't trusted there. handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator; - return new HttpClient(handler); + return new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(200) }; } } diff --git a/src/Servers/IIS/IIS/test/IIS.Shared.FunctionalTests/StdOutRedirectionTests.cs b/src/Servers/IIS/IIS/test/IIS.Shared.FunctionalTests/StdOutRedirectionTests.cs index e880e37ac8..260919c6de 100644 --- a/src/Servers/IIS/IIS/test/IIS.Shared.FunctionalTests/StdOutRedirectionTests.cs +++ b/src/Servers/IIS/IIS/test/IIS.Shared.FunctionalTests/StdOutRedirectionTests.cs @@ -47,7 +47,9 @@ public class StdOutRedirectionTests : IISFunctionalTestBase StopServer(); EventLogHelpers.VerifyEventLogEvent(deploymentResult, - @"The framework 'Microsoft.NETCore.App', version '2.9.9' \(x64\) was not found.", Logger); + @"Framework: 'Microsoft.NETCore.App', version '2.9.9' \(x64\)", Logger); + EventLogHelpers.VerifyEventLogEvent(deploymentResult, + "To install missing framework, download:", Logger); } [ConditionalFact] @@ -69,10 +71,13 @@ public class StdOutRedirectionTests : IISFunctionalTestBase StopServer(); var contents = Helpers.ReadAllTextFromFile(Helpers.GetExpectedLogName(deploymentResult, LogFolderPath), Logger); - var expectedString = "The framework 'Microsoft.NETCore.App', version '2.9.9' (x64) was not found."; + var missingFrameworkString = "To install missing framework, download:"; + EventLogHelpers.VerifyEventLogEvent(deploymentResult, + @"Framework: 'Microsoft.NETCore.App', version '2.9.9' \(x64\)", Logger); EventLogHelpers.VerifyEventLogEvent(deploymentResult, - @"The framework 'Microsoft.NETCore.App', version '2.9.9' \(x64\) was not found.", Logger); - Assert.Contains(expectedString, contents); + missingFrameworkString, Logger); + Assert.Contains(@"Framework: 'Microsoft.NETCore.App', version '2.9.9' (x64)", contents); + Assert.Contains(missingFrameworkString, contents); } [ConditionalFact] diff --git a/src/Servers/IIS/IIS/test/IIS.Tests/Utilities/TestServer.cs b/src/Servers/IIS/IIS/test/IIS.Tests/Utilities/TestServer.cs index 3bedbf730b..a4bd602edc 100644 --- a/src/Servers/IIS/IIS/test/IIS.Tests/Utilities/TestServer.cs +++ b/src/Servers/IIS/IIS/test/IIS.Tests/Utilities/TestServer.cs @@ -106,7 +106,8 @@ public class TestServer : IDisposable HttpClient = new HttpClient(new LoggingHandler(new SocketsHttpHandler(), _loggerFactory.CreateLogger<TestServer>())) { - BaseAddress = BaseUri + BaseAddress = BaseUri, + Timeout = TimeSpan.FromSeconds(200), }; } diff --git a/src/Servers/IIS/IIS/test/IISExpress.FunctionalTests/InProcess/WebSocketTests.cs b/src/Servers/IIS/IIS/test/IISExpress.FunctionalTests/InProcess/WebSocketTests.cs index 5911a68b89..65da17c282 100644 --- a/src/Servers/IIS/IIS/test/IISExpress.FunctionalTests/InProcess/WebSocketTests.cs +++ b/src/Servers/IIS/IIS/test/IISExpress.FunctionalTests/InProcess/WebSocketTests.cs @@ -31,7 +31,7 @@ public class WebSocketsTests [ConditionalFact] public async Task RequestWithBody_NotUpgradable() { - using var client = new HttpClient(); + using var client = new HttpClient() { Timeout = TimeSpan.FromSeconds(200) }; using var response = await client.PostAsync(_requestUri + "WebSocketNotUpgradable", new StringContent("Hello World")); response.EnsureSuccessStatusCode(); } @@ -39,7 +39,7 @@ public class WebSocketsTests [ConditionalFact] public async Task RequestWithoutBody_Upgradable() { - using var client = new HttpClient(); + using var client = new HttpClient() { Timeout = TimeSpan.FromSeconds(200) }; // POST with Content-Length: 0 counts as not having a body. using var response = await client.PostAsync(_requestUri + "WebSocketUpgradable", new StringContent("")); response.EnsureSuccessStatusCode(); diff --git a/src/Servers/IIS/IIS/test/testassets/IIS.Common.TestLib/TestConnections.cs b/src/Servers/IIS/IIS/test/testassets/IIS.Common.TestLib/TestConnections.cs index f61a24d099..5e470444ed 100644 --- a/src/Servers/IIS/IIS/test/testassets/IIS.Common.TestLib/TestConnections.cs +++ b/src/Servers/IIS/IIS/test/testassets/IIS.Common.TestLib/TestConnections.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting; /// </summary> public class TestConnection : IDisposable { - private static readonly TimeSpan Timeout = TimeSpan.FromMinutes(1); + private static readonly TimeSpan Timeout = TimeSpan.FromMinutes(2); private readonly bool _ownsSocket; private readonly Socket _socket; diff --git a/src/Servers/IIS/IIS/test/testassets/IIS.Common.TestLib/TimeoutExtensions.cs b/src/Servers/IIS/IIS/test/testassets/IIS.Common.TestLib/TimeoutExtensions.cs index 1031829c15..6651f4cf5a 100644 --- a/src/Servers/IIS/IIS/test/testassets/IIS.Common.TestLib/TimeoutExtensions.cs +++ b/src/Servers/IIS/IIS/test/testassets/IIS.Common.TestLib/TimeoutExtensions.cs @@ -10,5 +10,5 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting; public static class TimeoutExtensions { - public static TimeSpan DefaultTimeoutValue = TimeSpan.FromSeconds(300); + public static TimeSpan DefaultTimeoutValue = TimeSpan.FromMinutes(10); } diff --git a/src/Servers/IIS/IISIntegration/test/Tests/IISMiddlewareTests.cs b/src/Servers/IIS/IISIntegration/test/Tests/IISMiddlewareTests.cs index 15fb0ec4d4..d431f8925b 100644 --- a/src/Servers/IIS/IISIntegration/test/Tests/IISMiddlewareTests.cs +++ b/src/Servers/IIS/IISIntegration/test/Tests/IISMiddlewareTests.cs @@ -135,7 +135,7 @@ public class IISMiddlewareTests request.Headers.TryAddWithoutValidation("MS-ASPNETCORE-EVENT", shutdownEvent); var response = await server.CreateClient().SendAsync(request); - await applicationStoppingFired.Task.TimeoutAfter(TimeSpan.FromSeconds(5)); + await applicationStoppingFired.Task.TimeoutAfter(TimeSpan.FromSeconds(10)); Assert.False(requestExecuted.Task.IsCompleted); Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); } @@ -195,7 +195,7 @@ public class IISMiddlewareTests var response = await server.CreateClient().SendAsync(request); Assert.False(applicationStoppingFired.Task.IsCompleted); - await requestExecuted.Task.TimeoutAfter(TimeSpan.FromSeconds(1)); + await requestExecuted.Task.TimeoutAfter(TimeSpan.FromSeconds(2)); Assert.Equal(HttpStatusCode.OK, response.StatusCode); } @@ -240,7 +240,7 @@ public class IISMiddlewareTests var response = await server.CreateClient().SendAsync(request); Assert.False(applicationStoppingFired.Task.IsCompleted); - await requestExecuted.Task.TimeoutAfter(TimeSpan.FromSeconds(1)); + await requestExecuted.Task.TimeoutAfter(TimeSpan.FromSeconds(2)); Assert.Equal(HttpStatusCode.OK, response.StatusCode); } @@ -285,7 +285,7 @@ public class IISMiddlewareTests var response = await server.CreateClient().SendAsync(request); Assert.False(applicationStoppingFired.Task.IsCompleted); - await requestExecuted.Task.TimeoutAfter(TimeSpan.FromSeconds(1)); + await requestExecuted.Task.TimeoutAfter(TimeSpan.FromSeconds(2)); Assert.Equal(HttpStatusCode.OK, response.StatusCode); } diff --git a/src/Servers/IIS/IntegrationTesting.IIS/src/IISDeploymentResult.cs b/src/Servers/IIS/IntegrationTesting.IIS/src/IISDeploymentResult.cs index b81c145ee7..043852daa8 100644 --- a/src/Servers/IIS/IntegrationTesting.IIS/src/IISDeploymentResult.cs +++ b/src/Servers/IIS/IntegrationTesting.IIS/src/IISDeploymentResult.cs @@ -33,7 +33,8 @@ public class IISDeploymentResult : DeploymentResult { return new HttpClient(new LoggingHandler(messageHandler, Logger)) { - BaseAddress = base.HttpClient.BaseAddress + BaseAddress = base.HttpClient.BaseAddress, + Timeout = TimeSpan.FromSeconds(200), }; } diff --git a/src/Servers/IIS/IntegrationTesting.IIS/src/IISExpressDeployer.cs b/src/Servers/IIS/IntegrationTesting.IIS/src/IISExpressDeployer.cs index 927222da0f..9c3b101371 100644 --- a/src/Servers/IIS/IntegrationTesting.IIS/src/IISExpressDeployer.cs +++ b/src/Servers/IIS/IntegrationTesting.IIS/src/IISExpressDeployer.cs @@ -21,7 +21,7 @@ public class IISExpressDeployer : IISDeployerBase private const string FailedToInitializeBindingsMessage = "Failed to initialize site bindings"; private const string UnableToStartIISExpressMessage = "Unable to start iisexpress."; private const int MaximumAttempts = 5; - private readonly TimeSpan ShutdownTimeSpan = Debugger.IsAttached ? TimeSpan.FromMinutes(60) : TimeSpan.FromMinutes(1); + private readonly TimeSpan ShutdownTimeSpan = Debugger.IsAttached ? TimeSpan.FromMinutes(60) : TimeSpan.FromMinutes(2); private static readonly Regex UrlDetectorRegex = new Regex(@"^\s*Successfully registered URL ""(?<url>[^""]+)"" for site.*$"); private Process _hostProcess; @@ -234,10 +234,10 @@ public class IISExpressDeployer : IISDeployerBase } // Wait for the app to start - // The timeout here is large, because we don't know how long the test could need - // We cover a lot of error cases above, but I want to make sure we eventually give up and don't hang the build + // The timeout here is large, because we don't know how long the test could need. We cover a lot + // of error cases above, but I want to make sure we eventually give up and don't hang the build // just in case we missed one -anurse - if (!await started.Task.TimeoutAfter(TimeSpan.FromMinutes(10))) + if (!await started.Task.TimeoutAfter(TimeSpan.FromMinutes(15))) { Logger.LogInformation("iisexpress Process {pid} failed to bind to port {port}, trying again", process.Id, port); diff --git a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2FrameWriter.cs b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2FrameWriter.cs index d04e6b74c6..cec7e6d535 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2FrameWriter.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2FrameWriter.cs @@ -172,8 +172,19 @@ internal class Http2FrameWriter | Padding (*) ... +---------------------------------------------------------------+ */ - public void WriteResponseHeaders(int streamId, int statusCode, Http2HeadersFrameFlags headerFrameFlags, HttpResponseHeaders headers) + public void WriteResponseHeaders(Http2Stream stream, int statusCode, bool endStream, HttpResponseHeaders headers) { + Http2HeadersFrameFlags headerFrameFlags; + if (endStream) + { + headerFrameFlags = Http2HeadersFrameFlags.END_STREAM; + stream.DecrementActiveClientStreamCount(); + } + else + { + headerFrameFlags = Http2HeadersFrameFlags.NONE; + } + lock (_writeLock) { if (_completed) @@ -184,24 +195,26 @@ internal class Http2FrameWriter try { _headersEnumerator.Initialize(headers); - _outgoingFrame.PrepareHeaders(headerFrameFlags, streamId); + _outgoingFrame.PrepareHeaders(headerFrameFlags, stream.StreamId); var buffer = _headerEncodingBuffer.AsSpan(); var done = HPackHeaderWriter.BeginEncodeHeaders(statusCode, _hpackEncoder, _headersEnumerator, buffer, out var payloadLength); - FinishWritingHeaders(streamId, payloadLength, done); + FinishWritingHeaders(stream.StreamId, payloadLength, done); } // Any exception from the HPack encoder can leave the dynamic table in a corrupt state. // Since we allow custom header encoders we don't know what type of exceptions to expect. catch (Exception ex) { - _log.HPackEncodingError(_connectionId, streamId, ex); + _log.HPackEncodingError(_connectionId, stream.StreamId, ex); _http2Connection.Abort(new ConnectionAbortedException(ex.Message, ex)); throw new InvalidOperationException(ex.Message, ex); // Report the error to the user if this was the first write. } } } - public ValueTask<FlushResult> WriteResponseTrailersAsync(int streamId, HttpResponseTrailers headers) + public ValueTask<FlushResult> WriteResponseTrailersAsync(Http2Stream stream, HttpResponseTrailers headers) { + stream.DecrementActiveClientStreamCount(); + lock (_writeLock) { if (_completed) @@ -212,16 +225,16 @@ internal class Http2FrameWriter try { _headersEnumerator.Initialize(headers); - _outgoingFrame.PrepareHeaders(Http2HeadersFrameFlags.END_STREAM, streamId); + _outgoingFrame.PrepareHeaders(Http2HeadersFrameFlags.END_STREAM, stream.StreamId); var buffer = _headerEncodingBuffer.AsSpan(); var done = HPackHeaderWriter.BeginEncodeHeaders(_hpackEncoder, _headersEnumerator, buffer, out var payloadLength); - FinishWritingHeaders(streamId, payloadLength, done); + FinishWritingHeaders(stream.StreamId, payloadLength, done); } // Any exception from the HPack encoder can leave the dynamic table in a corrupt state. // Since we allow custom header encoders we don't know what type of exceptions to expect. catch (Exception ex) { - _log.HPackEncodingError(_connectionId, streamId, ex); + _log.HPackEncodingError(_connectionId, stream.StreamId, ex); _http2Connection.Abort(new ConnectionAbortedException(ex.Message, ex)); } @@ -258,7 +271,7 @@ internal class Http2FrameWriter } } - public ValueTask<FlushResult> WriteDataAsync(int streamId, StreamOutputFlowControl flowControl, in ReadOnlySequence<byte> data, bool endStream, bool firstWrite, bool forceFlush) + public ValueTask<FlushResult> WriteDataAsync(Http2Stream stream, StreamOutputFlowControl flowControl, in ReadOnlySequence<byte> data, bool endStream, bool firstWrite, bool forceFlush) { // Logic in this method is replicated in WriteDataAndTrailersAsync. // Changes here may need to be mirrored in WriteDataAndTrailersAsync. @@ -277,12 +290,12 @@ internal class Http2FrameWriter // https://httpwg.org/specs/rfc7540.html#rfc.section.6.9.1 if (dataLength != 0 && dataLength > flowControl.Available) { - return WriteDataAsync(streamId, flowControl, data, dataLength, endStream, firstWrite); + return WriteDataAsync(stream, flowControl, data, dataLength, endStream, firstWrite); } // This cast is safe since if dataLength would overflow an int, it's guaranteed to be greater than the available flow control window. flowControl.Advance((int)dataLength); - WriteDataUnsynchronized(streamId, data, dataLength, endStream); + WriteDataUnsynchronized(stream, data, dataLength, endStream); if (forceFlush) { @@ -293,7 +306,7 @@ internal class Http2FrameWriter } } - public ValueTask<FlushResult> WriteDataAndTrailersAsync(int streamId, StreamOutputFlowControl flowControl, in ReadOnlySequence<byte> data, bool firstWrite, HttpResponseTrailers headers) + public ValueTask<FlushResult> WriteDataAndTrailersAsync(Http2Stream stream, StreamOutputFlowControl flowControl, in ReadOnlySequence<byte> data, bool firstWrite, HttpResponseTrailers headers) { // This method combines WriteDataAsync and WriteResponseTrailers. // Changes here may need to be mirrored in WriteDataAsync. @@ -312,21 +325,21 @@ internal class Http2FrameWriter // https://httpwg.org/specs/rfc7540.html#rfc.section.6.9.1 if (dataLength != 0 && dataLength > flowControl.Available) { - return WriteDataAndTrailersAsyncCore(this, streamId, flowControl, data, dataLength, firstWrite, headers); + return WriteDataAndTrailersAsyncCore(this, stream, flowControl, data, dataLength, firstWrite, headers); } // This cast is safe since if dataLength would overflow an int, it's guaranteed to be greater than the available flow control window. flowControl.Advance((int)dataLength); - WriteDataUnsynchronized(streamId, data, dataLength, endStream: false); + WriteDataUnsynchronized(stream, data, dataLength, endStream: false); - return WriteResponseTrailersAsync(streamId, headers); + return WriteResponseTrailersAsync(stream, headers); } - static async ValueTask<FlushResult> WriteDataAndTrailersAsyncCore(Http2FrameWriter writer, int streamId, StreamOutputFlowControl flowControl, ReadOnlySequence<byte> data, long dataLength, bool firstWrite, HttpResponseTrailers headers) + static async ValueTask<FlushResult> WriteDataAndTrailersAsyncCore(Http2FrameWriter writer, Http2Stream stream, StreamOutputFlowControl flowControl, ReadOnlySequence<byte> data, long dataLength, bool firstWrite, HttpResponseTrailers headers) { - await writer.WriteDataAsync(streamId, flowControl, data, dataLength, endStream: false, firstWrite); + await writer.WriteDataAsync(stream, flowControl, data, dataLength, endStream: false, firstWrite); - return await writer.WriteResponseTrailersAsync(streamId, headers); + return await writer.WriteResponseTrailersAsync(stream, headers); } } @@ -339,12 +352,12 @@ internal class Http2FrameWriter | Padding (*) ... +---------------------------------------------------------------+ */ - private void WriteDataUnsynchronized(int streamId, in ReadOnlySequence<byte> data, long dataLength, bool endStream) + private void WriteDataUnsynchronized(Http2Stream stream, in ReadOnlySequence<byte> data, long dataLength, bool endStream) { Debug.Assert(dataLength == data.Length); // Note padding is not implemented - _outgoingFrame.PrepareData(streamId); + _outgoingFrame.PrepareData(stream.StreamId); if (dataLength > _maxFrameSize) // Minus padding { @@ -352,16 +365,7 @@ internal class Http2FrameWriter return; } - if (endStream) - { - _outgoingFrame.DataFlags |= Http2DataFrameFlags.END_STREAM; - } - - _outgoingFrame.PayloadLength = (int)dataLength; // Plus padding - - WriteHeaderUnsynchronized(); - - data.CopyTo(_outputWriter); + WriteDataUnsynchronizedCore(stream, endStream, dataLength, data); // Plus padding return; @@ -378,14 +382,8 @@ internal class Http2FrameWriter do { var currentData = remainingData.Slice(0, dataPayloadLength); - _outgoingFrame.PayloadLength = dataPayloadLength; // Plus padding - WriteHeaderUnsynchronized(); - - foreach (var buffer in currentData) - { - _outputWriter.Write(buffer.Span); - } + WriteDataUnsynchronizedCore(stream, endStream: false, dataPayloadLength, currentData); // Plus padding dataLength -= dataPayloadLength; @@ -393,25 +391,37 @@ internal class Http2FrameWriter } while (dataLength > dataPayloadLength); + WriteDataUnsynchronizedCore(stream, endStream, dataLength, remainingData); + + // Plus padding + } + + void WriteDataUnsynchronizedCore(Http2Stream stream, bool endStream, long dataLength, in ReadOnlySequence<byte> data) + { + Debug.Assert(dataLength == data.Length); + if (endStream) { _outgoingFrame.DataFlags |= Http2DataFrameFlags.END_STREAM; + + // When writing data, must decrement active stream count after flow control availability is checked. + // If active stream count becomes zero while a graceful shutdown is in progress then the input side of connection is closed. + // This is a problem if a large amount of data is being written. The server must keep processing incoming WINDOW_UPDATE frames. + // No WINDOW_UPDATE frames means response write could hit flow control and hang. + // Decrement also has to happen before writing END_STREAM to client to avoid race over active stream count. + stream.DecrementActiveClientStreamCount(); } + // It can be expensive to get length from ROS. Use already available value. _outgoingFrame.PayloadLength = (int)dataLength; // Plus padding WriteHeaderUnsynchronized(); - foreach (var buffer in remainingData) - { - _outputWriter.Write(buffer.Span); - } - - // Plus padding + data.CopyTo(_outputWriter); } } - private async ValueTask<FlushResult> WriteDataAsync(int streamId, StreamOutputFlowControl flowControl, ReadOnlySequence<byte> data, long dataLength, bool endStream, bool firstWrite) + private async ValueTask<FlushResult> WriteDataAsync(Http2Stream stream, StreamOutputFlowControl flowControl, ReadOnlySequence<byte> data, long dataLength, bool endStream, bool firstWrite) { FlushResult flushResult = default; @@ -436,13 +446,13 @@ internal class Http2FrameWriter { if (actual < dataLength) { - WriteDataUnsynchronized(streamId, data.Slice(0, actual), actual, endStream: false); + WriteDataUnsynchronized(stream, data.Slice(0, actual), actual, endStream: false); data = data.Slice(actual); dataLength -= actual; } else { - WriteDataUnsynchronized(streamId, data, actual, endStream); + WriteDataUnsynchronized(stream, data, actual, endStream); dataLength = 0; } diff --git a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2OutputProducer.cs b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2OutputProducer.cs index fb507c02e5..c138befdf1 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2OutputProducer.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2OutputProducer.cs @@ -203,20 +203,11 @@ internal class Http2OutputProducer : IHttpOutputProducer, IHttpOutputAborter, IV // The headers will be the final frame if: // 1. There is no content // 2. There is no trailing HEADERS frame. - Http2HeadersFrameFlags http2HeadersFrame; + _streamEnded = appCompleted + && !_startedWritingDataFrames + && (_stream.ResponseTrailers == null || _stream.ResponseTrailers.Count == 0); - if (appCompleted && !_startedWritingDataFrames && (_stream.ResponseTrailers == null || _stream.ResponseTrailers.Count == 0)) - { - _streamEnded = true; - _stream.DecrementActiveClientStreamCount(); - http2HeadersFrame = Http2HeadersFrameFlags.END_STREAM; - } - else - { - http2HeadersFrame = Http2HeadersFrameFlags.NONE; - } - - _frameWriter.WriteResponseHeaders(StreamId, statusCode, http2HeadersFrame, responseHeaders); + _frameWriter.WriteResponseHeaders(_stream, statusCode, _streamEnded, responseHeaders); } } @@ -429,16 +420,15 @@ internal class Http2OutputProducer : IHttpOutputProducer, IHttpOutputAborter, IV // Write any remaining content then write trailers _stream.ResponseTrailers.SetReadOnly(); - _stream.DecrementActiveClientStreamCount(); if (readResult.Buffer.Length > 0) { // It is faster to write data and trailers together. Locking once reduces lock contention. - flushResult = await _frameWriter.WriteDataAndTrailersAsync(StreamId, _flowControl, readResult.Buffer, firstWrite, _stream.ResponseTrailers); + flushResult = await _frameWriter.WriteDataAndTrailersAsync(_stream, _flowControl, readResult.Buffer, firstWrite, _stream.ResponseTrailers); } else { - flushResult = await _frameWriter.WriteResponseTrailersAsync(StreamId, _stream.ResponseTrailers); + flushResult = await _frameWriter.WriteResponseTrailersAsync(_stream, _stream.ResponseTrailers); } } else if (readResult.IsCompleted && _streamEnded) @@ -454,13 +444,7 @@ internal class Http2OutputProducer : IHttpOutputProducer, IHttpOutputAborter, IV else { var endStream = readResult.IsCompleted; - - if (endStream) - { - _stream.DecrementActiveClientStreamCount(); - } - - flushResult = await _frameWriter.WriteDataAsync(StreamId, _flowControl, readResult.Buffer, endStream, firstWrite, forceFlush: true); + flushResult = await _frameWriter.WriteDataAsync(_stream, _flowControl, readResult.Buffer, endStream, firstWrite, forceFlush: true); } firstWrite = false; diff --git a/src/Servers/Kestrel/perf/Microbenchmarks/Http2/Http2FrameWriterBenchmark.cs b/src/Servers/Kestrel/perf/Microbenchmarks/Http2/Http2FrameWriterBenchmark.cs index 3a2844125c..bb5d2d7d8b 100644 --- a/src/Servers/Kestrel/perf/Microbenchmarks/Http2/Http2FrameWriterBenchmark.cs +++ b/src/Servers/Kestrel/perf/Microbenchmarks/Http2/Http2FrameWriterBenchmark.cs @@ -20,6 +20,7 @@ public class Http2FrameWriterBenchmark private Pipe _pipe; private Http2FrameWriter _frameWriter; private HttpResponseHeaders _responseHeaders; + private Http2Stream _stream; [GlobalSetup] public void GlobalSetup() @@ -45,6 +46,8 @@ public class Http2FrameWriterBenchmark _memoryPool, serviceContext); + _stream = new MockHttp2Stream(TestContextFactory.CreateHttp2StreamContext(streamId: 0)); + _responseHeaders = new HttpResponseHeaders(); var headers = (IHeaderDictionary)_responseHeaders; headers.ContentType = "application/json"; @@ -54,7 +57,7 @@ public class Http2FrameWriterBenchmark [Benchmark] public void WriteResponseHeaders() { - _frameWriter.WriteResponseHeaders(0, 200, Http2HeadersFrameFlags.END_HEADERS, _responseHeaders); + _frameWriter.WriteResponseHeaders(_stream, 200, endStream: true, _responseHeaders); } [GlobalCleanup] @@ -63,4 +66,16 @@ public class Http2FrameWriterBenchmark _pipe.Writer.Complete(); _memoryPool?.Dispose(); } + + private class MockHttp2Stream : Http2Stream + { + public MockHttp2Stream(Http2StreamContext context) + { + Initialize(context); + } + + public override void Execute() + { + } + } } diff --git a/src/Servers/Kestrel/shared/test/TestContextFactory.cs b/src/Servers/Kestrel/shared/test/TestContextFactory.cs index 0f1fdba1f7..14df1153cb 100644 --- a/src/Servers/Kestrel/shared/test/TestContextFactory.cs +++ b/src/Servers/Kestrel/shared/test/TestContextFactory.cs @@ -155,7 +155,7 @@ internal static class TestContextFactory localEndPoint: localEndPoint, remoteEndPoint: remoteEndPoint, streamId: streamId ?? 0, - streamLifetimeHandler: streamLifetimeHandler, + streamLifetimeHandler: streamLifetimeHandler ?? new TestHttp2StreamLifetimeHandler(), clientPeerSettings: clientPeerSettings ?? new Http2PeerSettings(), serverPeerSettings: serverPeerSettings ?? new Http2PeerSettings(), frameWriter: frameWriter, @@ -201,6 +201,17 @@ internal static class TestContextFactory return context; } + private class TestHttp2StreamLifetimeHandler : IHttp2StreamLifetimeHandler + { + public void DecrementActiveClientStreamCount() + { + } + + public void OnStreamCompleted(Http2Stream stream) + { + } + } + private class TestMultiplexedConnectionContext : MultiplexedConnectionContext { public override string ConnectionId { get; set; } diff --git a/src/Servers/Kestrel/test/Interop.FunctionalTests/Http2/Http2RequestTests.cs b/src/Servers/Kestrel/test/Interop.FunctionalTests/Http2/Http2RequestTests.cs index 142fb55770..59834b29ef 100644 --- a/src/Servers/Kestrel/test/Interop.FunctionalTests/Http2/Http2RequestTests.cs +++ b/src/Servers/Kestrel/test/Interop.FunctionalTests/Http2/Http2RequestTests.cs @@ -3,11 +3,16 @@ using System.Net; using System.Net.Http; +using System.Net.Http.Headers; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Headers; +using Microsoft.AspNetCore.Internal; using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.AspNetCore.Testing; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; namespace Interop.FunctionalTests.Http2; @@ -37,6 +42,94 @@ public class Http2RequestTests : LoggedTest } } + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task GET_RequestReturnsLargeData_GracefulShutdownDuringRequest_RequestGracefullyCompletes(bool hasTrailers) + { + // Arrange + const int DataLength = 500_000; + var randomBytes = Enumerable.Range(1, DataLength).Select(i => (byte)((i % 10) + 48)).ToArray(); + + var syncPoint = new SyncPoint(); + + ILogger logger = null; + var builder = CreateHostBuilder( + async c => + { + await syncPoint.WaitToContinue(); + + var memory = c.Response.BodyWriter.GetMemory(randomBytes.Length); + + logger.LogInformation($"Server writing {randomBytes.Length} bytes response"); + randomBytes.CopyTo(memory); + + // It's important for this test that the large write is the last data written to + // the response and it's not awaited by the request delegate. + logger.LogInformation($"Server advancing {randomBytes.Length} bytes response"); + c.Response.BodyWriter.Advance(randomBytes.Length); + + if (hasTrailers) + { + c.Response.AppendTrailer("test-trailer", "value!"); + } + }, + protocol: HttpProtocols.Http2, + plaintext: true); + + using var host = builder.Build(); + logger = host.Services.GetRequiredService<ILoggerFactory>().CreateLogger("Test"); + + var client = HttpHelpers.CreateClient(); + + // Act + await host.StartAsync().DefaultTimeout(); + + var longRunningTask = StartLongRunningRequestAsync(logger, host, client); + + logger.LogInformation("Waiting for request on server"); + await syncPoint.WaitForSyncPoint().DefaultTimeout(); + + logger.LogInformation("Stopping server"); + var stopTask = host.StopAsync(); + + syncPoint.Continue(); + + var (readData, trailers) = await longRunningTask.DefaultTimeout(); + await stopTask.DefaultTimeout(); + + // Assert + Assert.Equal(randomBytes, readData); + if (hasTrailers) + { + Assert.Equal("value!", trailers.GetValues("test-trailer").Single()); + } + } + + private static async Task<(byte[], HttpResponseHeaders)> StartLongRunningRequestAsync(ILogger logger, IHost host, HttpMessageInvoker client) + { + var request = new HttpRequestMessage(HttpMethod.Get, $"http://127.0.0.1:{host.GetPort()}/"); + request.Version = HttpVersion.Version20; + request.VersionPolicy = HttpVersionPolicy.RequestVersionExact; + + var responseMessage = await client.SendAsync(request, CancellationToken.None).DefaultTimeout(); + responseMessage.EnsureSuccessStatusCode(); + + var responseStream = await responseMessage.Content.ReadAsStreamAsync(); + + var data = new List<byte>(); + var buffer = new byte[1024 * 128]; + int readCount; + while ((readCount = await responseStream.ReadAsync(buffer)) != 0) + { + data.AddRange(buffer.AsMemory(0, readCount).ToArray()); + logger.LogInformation($"Received {readCount} bytes. Total {data.Count} bytes."); + } + logger.LogInformation($"Finished reading response content"); + + return (data.ToArray(), responseMessage.TrailingHeaders); + } + private IHostBuilder CreateHostBuilder(RequestDelegate requestDelegate, HttpProtocols? protocol = null, Action<KestrelServerOptions> configureKestrel = null, bool? plaintext = null) { return HttpHelpers.CreateHostBuilder(AddTestLogging, requestDelegate, protocol, configureKestrel, plaintext); diff --git a/src/Servers/Kestrel/test/Interop.FunctionalTests/HttpHelpers.cs b/src/Servers/Kestrel/test/Interop.FunctionalTests/HttpHelpers.cs index dcb49dd6ce..6dec979584 100644 --- a/src/Servers/Kestrel/test/Interop.FunctionalTests/HttpHelpers.cs +++ b/src/Servers/Kestrel/test/Interop.FunctionalTests/HttpHelpers.cs @@ -81,7 +81,7 @@ internal static class HttpHelpers } else { - o.ShutdownTimeout = TimeSpan.FromSeconds(1); + o.ShutdownTimeout = TimeSpan.FromSeconds(5); } }); } diff --git a/src/Shared/HttpValidationProblemDetailsJsonConverter.cs b/src/Shared/HttpValidationProblemDetailsJsonConverter.cs index c2981548f2..9c8bd17871 100644 --- a/src/Shared/HttpValidationProblemDetailsJsonConverter.cs +++ b/src/Shared/HttpValidationProblemDetailsJsonConverter.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; using System.Text.Json; using System.Text.Json.Serialization; @@ -10,12 +11,14 @@ internal sealed class HttpValidationProblemDetailsJsonConverter : JsonConverter< { private static readonly JsonEncodedText Errors = JsonEncodedText.Encode("errors"); + [UnconditionalSuppressMessage("Trimmer", "IL2026", Justification = "Trimmer does not allow annotating overriden methods with annotations different from the ones in base type.")] public override HttpValidationProblemDetails Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var problemDetails = new HttpValidationProblemDetails(); return ReadProblemDetails(ref reader, options, problemDetails); } + [RequiresUnreferencedCode("JSON serialization and deserialization ProblemDetails.Extensions might require types that cannot be statically analyzed. ")] public static HttpValidationProblemDetails ReadProblemDetails(ref Utf8JsonReader reader, JsonSerializerOptions options, HttpValidationProblemDetails problemDetails) { if (reader.TokenType != JsonTokenType.StartObject) @@ -27,7 +30,7 @@ internal sealed class HttpValidationProblemDetailsJsonConverter : JsonConverter< { if (reader.ValueTextEquals(Errors.EncodedUtf8Bytes)) { - var errors = JsonSerializer.Deserialize<Dictionary<string, string[]>>(ref reader, options); + var errors = DeserializeErrors(ref reader, options); if (errors is not null) { foreach (var item in errors) @@ -48,21 +51,33 @@ internal sealed class HttpValidationProblemDetailsJsonConverter : JsonConverter< } return problemDetails; + + [UnconditionalSuppressMessage("Trimmer", "IL2026", Justification = "We ensure Dictionary<string, string[]> is preserved.")] + [DynamicDependency(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicProperties, typeof(Dictionary<string, string[]>))] + static Dictionary<string, string[]>? DeserializeErrors(ref Utf8JsonReader reader, JsonSerializerOptions options) + => JsonSerializer.Deserialize<Dictionary<string, string[]>>(ref reader, options); } + [UnconditionalSuppressMessage("Trimmer", "IL2026", Justification = "Trimmer does not allow annotating overriden methods with annotations different from the ones in base type.")] public override void Write(Utf8JsonWriter writer, HttpValidationProblemDetails value, JsonSerializerOptions options) { WriteProblemDetails(writer, value, options); } + [RequiresUnreferencedCode("JSON serialization and deserialization ProblemDetails.Extensions might require types that cannot be statically analyzed. ")] public static void WriteProblemDetails(Utf8JsonWriter writer, HttpValidationProblemDetails value, JsonSerializerOptions options) { writer.WriteStartObject(); ProblemDetailsJsonConverter.WriteProblemDetails(writer, value, options); writer.WritePropertyName(Errors); - JsonSerializer.Serialize(writer, value.Errors, options); + SerializeErrors(writer, value.Errors, options); writer.WriteEndObject(); + + [UnconditionalSuppressMessage("Trimmer", "IL2026", Justification = "We ensure IDictionary<string, string[]> is preserved.")] + [DynamicDependency(DynamicallyAccessedMemberTypes.PublicProperties, typeof(IDictionary<string, string[]>))] + static void SerializeErrors(Utf8JsonWriter writer, IDictionary<string, string[]> errors, JsonSerializerOptions options) + => JsonSerializer.Serialize(writer, errors, options); } } diff --git a/src/Shared/ObjectMethodExecutor/AwaitableInfo.cs b/src/Shared/ObjectMethodExecutor/AwaitableInfo.cs index 01529fbbdc..9b854ba7ea 100644 --- a/src/Shared/ObjectMethodExecutor/AwaitableInfo.cs +++ b/src/Shared/ObjectMethodExecutor/AwaitableInfo.cs @@ -1,10 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#nullable disable +#nullable enable -using System; -using System.Linq; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.CompilerServices; @@ -12,11 +11,15 @@ namespace Microsoft.Extensions.Internal; internal readonly struct AwaitableInfo { + private const BindingFlags Everything = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance; + private static readonly MethodInfo INotifyCompletion_OnCompleted = typeof(INotifyCompletion).GetMethod(nameof(INotifyCompletion.OnCompleted), Everything, new[] { typeof(Action) })!; + private static readonly MethodInfo ICriticalNotifyCompletion_UnsafeOnCompleted = typeof(ICriticalNotifyCompletion).GetMethod(nameof(ICriticalNotifyCompletion.UnsafeOnCompleted), Everything, new[] { typeof(Action) })!; + public Type AwaiterType { get; } public PropertyInfo AwaiterIsCompletedProperty { get; } public MethodInfo AwaiterGetResultMethod { get; } public MethodInfo AwaiterOnCompletedMethod { get; } - public MethodInfo AwaiterUnsafeOnCompletedMethod { get; } + public MethodInfo? AwaiterUnsafeOnCompletedMethod { get; } public Type ResultType { get; } public MethodInfo GetAwaiterMethod { get; } @@ -25,7 +28,7 @@ internal readonly struct AwaitableInfo PropertyInfo awaiterIsCompletedProperty, MethodInfo awaiterGetResultMethod, MethodInfo awaiterOnCompletedMethod, - MethodInfo awaiterUnsafeOnCompletedMethod, + MethodInfo? awaiterUnsafeOnCompletedMethod, Type resultType, MethodInfo getAwaiterMethod) { @@ -38,16 +41,18 @@ internal readonly struct AwaitableInfo GetAwaiterMethod = getAwaiterMethod; } - public static bool IsTypeAwaitable(Type type, out AwaitableInfo awaitableInfo) + [UnconditionalSuppressMessage("Trimmer", "IL2070", Justification = "Reflecting over the async Task types contract")] + [UnconditionalSuppressMessage("Trimmer", "IL2075", Justification = "Reflecting over the async Task types contract")] + public static bool IsTypeAwaitable( + Type type, + out AwaitableInfo awaitableInfo) { // Based on Roslyn code: http://source.roslyn.io/#Microsoft.CodeAnalysis.Workspaces/Shared/Extensions/ISymbolExtensions.cs,db4d48ba694b9347 // Awaitable must have method matching "object GetAwaiter()" - var getAwaiterMethod = type.GetRuntimeMethods().FirstOrDefault(m => - m.Name.Equals("GetAwaiter", StringComparison.OrdinalIgnoreCase) - && m.GetParameters().Length == 0 - && m.ReturnType != null); - if (getAwaiterMethod == null) + var getAwaiterMethod = type.GetMethod("GetAwaiter", Everything, Type.EmptyTypes); + + if (getAwaiterMethod is null) { awaitableInfo = default(AwaitableInfo); return false; @@ -56,19 +61,15 @@ internal readonly struct AwaitableInfo var awaiterType = getAwaiterMethod.ReturnType; // Awaiter must have property matching "bool IsCompleted { get; }" - var isCompletedProperty = awaiterType.GetRuntimeProperties().FirstOrDefault(p => - p.Name.Equals("IsCompleted", StringComparison.OrdinalIgnoreCase) - && p.PropertyType == typeof(bool) - && p.GetMethod != null); - if (isCompletedProperty == null) + var isCompletedProperty = awaiterType.GetProperty("IsCompleted", Everything, binder: null, returnType: typeof(bool), types: Type.EmptyTypes, modifiers: null); + if (isCompletedProperty is null) { awaitableInfo = default(AwaitableInfo); return false; } // Awaiter must implement INotifyCompletion - var awaiterInterfaces = awaiterType.GetInterfaces(); - var implementsINotifyCompletion = awaiterInterfaces.Any(t => t == typeof(INotifyCompletion)); + var implementsINotifyCompletion = typeof(INotifyCompletion).IsAssignableFrom(awaiterType); if (!implementsINotifyCompletion) { awaitableInfo = default(AwaitableInfo); @@ -76,34 +77,21 @@ internal readonly struct AwaitableInfo } // INotifyCompletion supplies a method matching "void OnCompleted(Action action)" - var onCompletedMethod = typeof(INotifyCompletion).GetRuntimeMethods().Single(m => - m.Name.Equals("OnCompleted", StringComparison.OrdinalIgnoreCase) - && m.ReturnType == typeof(void) - && m.GetParameters().Length == 1 - && m.GetParameters()[0].ParameterType == typeof(Action)); + var onCompletedMethod = INotifyCompletion_OnCompleted; // Awaiter optionally implements ICriticalNotifyCompletion - var implementsICriticalNotifyCompletion = awaiterInterfaces.Any(t => t == typeof(ICriticalNotifyCompletion)); - MethodInfo unsafeOnCompletedMethod; + var implementsICriticalNotifyCompletion = typeof(ICriticalNotifyCompletion).IsAssignableFrom(awaiterType); + MethodInfo? unsafeOnCompletedMethod = null; if (implementsICriticalNotifyCompletion) { // ICriticalNotifyCompletion supplies a method matching "void UnsafeOnCompleted(Action action)" - unsafeOnCompletedMethod = typeof(ICriticalNotifyCompletion).GetRuntimeMethods().Single(m => - m.Name.Equals("UnsafeOnCompleted", StringComparison.OrdinalIgnoreCase) - && m.ReturnType == typeof(void) - && m.GetParameters().Length == 1 - && m.GetParameters()[0].ParameterType == typeof(Action)); - } - else - { - unsafeOnCompletedMethod = null; + unsafeOnCompletedMethod = ICriticalNotifyCompletion_UnsafeOnCompleted; } // Awaiter must have method matching "void GetResult" or "T GetResult()" - var getResultMethod = awaiterType.GetRuntimeMethods().FirstOrDefault(m => - m.Name.Equals("GetResult") - && m.GetParameters().Length == 0); - if (getResultMethod == null) + var getResultMethod = awaiterType.GetMethod("GetResult", Everything, Type.EmptyTypes); + + if (getResultMethod is null) { awaitableInfo = default(AwaitableInfo); return false; diff --git a/src/Shared/ObjectMethodExecutor/CoercedAwaitableInfo.cs b/src/Shared/ObjectMethodExecutor/CoercedAwaitableInfo.cs index dbd6c5fb2b..d47f974735 100644 --- a/src/Shared/ObjectMethodExecutor/CoercedAwaitableInfo.cs +++ b/src/Shared/ObjectMethodExecutor/CoercedAwaitableInfo.cs @@ -3,7 +3,7 @@ #nullable disable -using System; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; namespace Microsoft.Extensions.Internal; @@ -29,7 +29,9 @@ internal readonly struct CoercedAwaitableInfo AwaitableInfo = coercedAwaitableInfo; } - public static bool IsTypeAwaitable(Type type, out CoercedAwaitableInfo info) + public static bool IsTypeAwaitable( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)] Type type, + out CoercedAwaitableInfo info) { if (AwaitableInfo.IsTypeAwaitable(type, out var directlyAwaitableInfo)) { diff --git a/src/Shared/ObjectMethodExecutor/ObjectMethodExecutor.cs b/src/Shared/ObjectMethodExecutor/ObjectMethodExecutor.cs index f6c0acda2e..52272f4208 100644 --- a/src/Shared/ObjectMethodExecutor/ObjectMethodExecutor.cs +++ b/src/Shared/ObjectMethodExecutor/ObjectMethodExecutor.cs @@ -3,15 +3,14 @@ #nullable enable -using System; -using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; using System.Reflection; namespace Microsoft.Extensions.Internal; -internal class ObjectMethodExecutor +internal sealed class ObjectMethodExecutor { private readonly object?[]? _parameterDefaultValues; private readonly MethodExecutorAsync? _executorAsync; @@ -19,14 +18,15 @@ internal class ObjectMethodExecutor private static readonly ConstructorInfo _objectMethodExecutorAwaitableConstructor = typeof(ObjectMethodExecutorAwaitable).GetConstructor(new[] { - typeof(object), // customAwaitable - typeof(Func<object, object>), // getAwaiterMethod - typeof(Func<object, bool>), // isCompletedMethod - typeof(Func<object, object>), // getResultMethod - typeof(Action<object, Action>), // onCompletedMethod - typeof(Action<object, Action>) // unsafeOnCompletedMethod - })!; - + typeof(object), // customAwaitable + typeof(Func<object, object>), // getAwaiterMethod + typeof(Func<object, bool>), // isCompletedMethod + typeof(Func<object, object>), // getResultMethod + typeof(Action<object, Action>), // onCompletedMethod + typeof(Action<object, Action>) // unsafeOnCompletedMethod + })!; + + [RequiresUnreferencedCode("This method performs reflection on arbitrary types.")] private ObjectMethodExecutor(MethodInfo methodInfo, TypeInfo targetTypeInfo, object?[]? parameterDefaultValues) { if (methodInfo == null) @@ -76,11 +76,13 @@ internal class ObjectMethodExecutor public bool IsMethodAsync { get; } + [RequiresUnreferencedCode("This method performs reflection on arbitrary types.")] public static ObjectMethodExecutor Create(MethodInfo methodInfo, TypeInfo targetTypeInfo) { return new ObjectMethodExecutor(methodInfo, targetTypeInfo, null); } + [RequiresUnreferencedCode("This method performs reflection on arbitrary types.")] public static ObjectMethodExecutor Create(MethodInfo methodInfo, TypeInfo targetTypeInfo, object?[] parameterDefaultValues) { if (parameterDefaultValues == null) diff --git a/src/Shared/ObjectMethodExecutor/ObjectMethodExecutorFSharpSupport.cs b/src/Shared/ObjectMethodExecutor/ObjectMethodExecutorFSharpSupport.cs index 473343748c..5b2a7389d2 100644 --- a/src/Shared/ObjectMethodExecutor/ObjectMethodExecutorFSharpSupport.cs +++ b/src/Shared/ObjectMethodExecutor/ObjectMethodExecutorFSharpSupport.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -29,6 +30,7 @@ internal static class ObjectMethodExecutorFSharpSupport private static PropertyInfo _fsharpOptionOfTaskCreationOptionsNoneProperty; private static PropertyInfo _fsharpOptionOfCancellationTokenNoneProperty; + [UnconditionalSuppressMessage("Trimmer", "IL2060", Justification = "Reflecting over the async FSharpAsync<> contract")] public static bool TryBuildCoercerFromFSharpAsyncToAwaitable( Type possibleFSharpAsyncType, out Expression coerceToAwaitableExpression, @@ -96,6 +98,9 @@ internal static class ObjectMethodExecutorFSharpSupport } } + [UnconditionalSuppressMessage("Trimmer", "IL2026", Justification = "Reflecting over the async FSharpAsync<> contract")] + [UnconditionalSuppressMessage("Trimmer", "IL2055", Justification = "Reflecting over the async FSharpAsync<> contract")] + [UnconditionalSuppressMessage("Trimmer", "IL2072", Justification = "Reflecting over the async FSharpAsync<> contract")] private static bool TryPopulateFSharpValueCaches(Type possibleFSharpAsyncGenericType) { var assembly = possibleFSharpAsyncGenericType.Assembly; diff --git a/src/Shared/ParameterBindingMethodCache.cs b/src/Shared/ParameterBindingMethodCache.cs index 2eb5acd77d..01b5c0895e 100644 --- a/src/Shared/ParameterBindingMethodCache.cs +++ b/src/Shared/ParameterBindingMethodCache.cs @@ -17,6 +17,9 @@ using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Http; +[UnconditionalSuppressMessage("Trimmer", "IL2060", Justification = "Trimmer warnings are presented in RequestDelegateFactory.")] +[UnconditionalSuppressMessage("Trimmer", "IL2065", Justification = "Trimmer warnings are presented in RequestDelegateFactory.")] +[UnconditionalSuppressMessage("Trimmer", "IL2070", Justification = "Trimmer warnings are presented in RequestDelegateFactory.")] internal sealed class ParameterBindingMethodCache { private static readonly MethodInfo ConvertValueTaskMethod = typeof(ParameterBindingMethodCache).GetMethod(nameof(ConvertValueTask), BindingFlags.NonPublic | BindingFlags.Static)!; @@ -208,8 +211,11 @@ internal sealed class ParameterBindingMethodCache { typedCall = Expression.Call(methodInfo, HttpContextExpr); } - return Expression.Call(ConvertValueTaskMethod.MakeGenericMethod(nonNullableParameterType), typedCall); + return Expression.Call(GetGenericConvertValueTask(nonNullableParameterType), typedCall); }, hasParameterInfo ? 2 : 1); + + [UnconditionalSuppressMessage("Trimmer", "IL2060", Justification = "Linker workaround. The type is annotated with RequiresUnreferencedCode")] + static MethodInfo GetGenericConvertValueTask(Type nonNullableParameterType) => ConvertValueTaskMethod.MakeGenericMethod(nonNullableParameterType); } // ValueTask<Nullable<{type}>>? else if (valueTaskResultType.IsGenericType && @@ -229,8 +235,11 @@ internal sealed class ParameterBindingMethodCache { typedCall = Expression.Call(methodInfo, HttpContextExpr); } - return Expression.Call(ConvertValueTaskOfNullableResultMethod.MakeGenericMethod(nonNullableParameterType), typedCall); + return Expression.Call(GetGenericConvertValueTaskOfNullableResult(nonNullableParameterType), typedCall); }, hasParameterInfo ? 2 : 1); + + [UnconditionalSuppressMessage("Trimmer", "IL2060", Justification = "Linker workaround. The type is annotated with RequiresUnreferencedCode")] + static MethodInfo GetGenericConvertValueTaskOfNullableResult(Type nonNullableParameterType) => ConvertValueTaskOfNullableResultMethod.MakeGenericMethod(nonNullableParameterType); } } diff --git a/src/Shared/ProblemDetailsJsonConverter.cs b/src/Shared/ProblemDetailsJsonConverter.cs index ad21142f3a..13120d36d2 100644 --- a/src/Shared/ProblemDetailsJsonConverter.cs +++ b/src/Shared/ProblemDetailsJsonConverter.cs @@ -16,6 +16,7 @@ internal sealed class ProblemDetailsJsonConverter : JsonConverter<ProblemDetails private static readonly JsonEncodedText Detail = JsonEncodedText.Encode("detail"); private static readonly JsonEncodedText Instance = JsonEncodedText.Encode("instance"); + [UnconditionalSuppressMessage("Trimmer", "IL2026", Justification = "Trimmer does not allow annotating overriden methods with annotations different from the ones in base type.")] public override ProblemDetails Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var problemDetails = new ProblemDetails(); @@ -38,6 +39,7 @@ internal sealed class ProblemDetailsJsonConverter : JsonConverter<ProblemDetails return problemDetails; } + [UnconditionalSuppressMessage("Trimmer", "IL2026", Justification = "Trimmer does not allow annotating overriden methods with annotations different from the ones in base type.")] public override void Write(Utf8JsonWriter writer, ProblemDetails value, JsonSerializerOptions options) { writer.WriteStartObject(); @@ -45,6 +47,7 @@ internal sealed class ProblemDetailsJsonConverter : JsonConverter<ProblemDetails writer.WriteEndObject(); } + [RequiresUnreferencedCode("JSON serialization and deserialization of ProblemDetails.Extensions might require types that cannot be statically analyzed.")] internal static void ReadValue(ref Utf8JsonReader reader, ProblemDetails value, JsonSerializerOptions options) { if (TryReadStringProperty(ref reader, Type, out var propertyValue)) @@ -96,6 +99,7 @@ internal sealed class ProblemDetailsJsonConverter : JsonConverter<ProblemDetails return true; } + [RequiresUnreferencedCode("JSON serialization and deserialization of ProblemDetails.Extensions might require types that cannot be statically analyzed.")] internal static void WriteProblemDetails(Utf8JsonWriter writer, ProblemDetails value, JsonSerializerOptions options) { if (value.Type != null) diff --git a/src/Shared/runtime/Http3/QPack/QPackDecoder.cs b/src/Shared/runtime/Http3/QPack/QPackDecoder.cs index 83e1b7f3a3..9e3d8fe8a2 100644 --- a/src/Shared/runtime/Http3/QPack/QPackDecoder.cs +++ b/src/Shared/runtime/Http3/QPack/QPackDecoder.cs @@ -710,7 +710,7 @@ namespace System.Net.Http.QPack _state = State.HeaderValueLength; } - private void OnIndexedHeaderNamePostBase(int index) + private static void OnIndexedHeaderNamePostBase(int index) { ThrowDynamicTableNotSupported(); // TODO update with postbase index @@ -718,7 +718,7 @@ namespace System.Net.Http.QPack // _state = State.HeaderValueLength; } - private void OnPostBaseIndex(int intResult, IHttpStreamHeadersHandler handler) + private static void OnPostBaseIndex(int intResult, IHttpStreamHeadersHandler handler) { ThrowDynamicTableNotSupported(); // TODO diff --git a/src/SignalR/clients/ts/FunctionalTests/package.json b/src/SignalR/clients/ts/FunctionalTests/package.json index fbe107c3df..67032e21c6 100644 --- a/src/SignalR/clients/ts/FunctionalTests/package.json +++ b/src/SignalR/clients/ts/FunctionalTests/package.json @@ -55,7 +55,8 @@ "resolutions": { "lodash": ">=4.17.21", "url-parse": ">=1.5.6", - "ua-parser-js": "^0.7.30" + "ua-parser-js": "^0.7.30", + "minimist": ">=1.2.6" }, "author": "", "license": "MIT" diff --git a/src/SignalR/clients/ts/FunctionalTests/yarn.lock b/src/SignalR/clients/ts/FunctionalTests/yarn.lock index 06a8997827..0cdc9768f1 100644 --- a/src/SignalR/clients/ts/FunctionalTests/yarn.lock +++ b/src/SignalR/clients/ts/FunctionalTests/yarn.lock @@ -2327,10 +2327,10 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +minimist@>=1.2.6, minimist@^1.2.5: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== mkdirp-classic@^0.5.2: version "0.5.3" diff --git a/src/SignalR/clients/ts/common/package.json b/src/SignalR/clients/ts/common/package.json index 34f9eaa675..9e72399596 100644 --- a/src/SignalR/clients/ts/common/package.json +++ b/src/SignalR/clients/ts/common/package.json @@ -33,6 +33,7 @@ "dependencies": {}, "resolutions": { "ansi-regex": "5.0.1", - "set-value": ">=4.0.1" + "set-value": ">=4.0.1", + "minimist": ">=1.2.6" } } diff --git a/src/SignalR/clients/ts/common/yarn.lock b/src/SignalR/clients/ts/common/yarn.lock index 141c7c07fe..d85d111daa 100644 --- a/src/SignalR/clients/ts/common/yarn.lock +++ b/src/SignalR/clients/ts/common/yarn.lock @@ -3365,10 +3365,10 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +minimist@>=1.2.6, minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== mixin-deep@^1.2.0: version "1.3.2" diff --git a/src/Tools/Tools.slnf b/src/Tools/Tools.slnf index 098504c6a2..3db571352b 100644 --- a/src/Tools/Tools.slnf +++ b/src/Tools/Tools.slnf @@ -11,11 +11,14 @@ "src\\Components\\WebAssembly\\WebAssembly\\src\\Microsoft.AspNetCore.Components.WebAssembly.csproj", "src\\Components\\Web\\src\\Microsoft.AspNetCore.Components.Web.csproj", "src\\Extensions\\Features\\src\\Microsoft.Extensions.Features.csproj", + "src\\Hosting\\Abstractions\\src\\Microsoft.AspNetCore.Hosting.Abstractions.csproj", + "src\\Hosting\\Server.Abstractions\\src\\Microsoft.AspNetCore.Hosting.Server.Abstractions.csproj", "src\\Http\\Headers\\src\\Microsoft.Net.Http.Headers.csproj", "src\\Http\\Http.Abstractions\\src\\Microsoft.AspNetCore.Http.Abstractions.csproj", "src\\Http\\Http.Features\\src\\Microsoft.AspNetCore.Http.Features.csproj", "src\\Http\\Http\\src\\Microsoft.AspNetCore.Http.csproj", "src\\Http\\Metadata\\src\\Microsoft.AspNetCore.Metadata.csproj", + "src\\Http\\Routing.Abstractions\\src\\Microsoft.AspNetCore.Routing.Abstractions.csproj", "src\\Http\\WebUtilities\\src\\Microsoft.AspNetCore.WebUtilities.csproj", "src\\JSInterop\\Microsoft.JSInterop\\src\\Microsoft.JSInterop.csproj", "src\\ObjectPool\\src\\Microsoft.Extensions.ObjectPool.csproj", diff --git a/src/submodules/googletest b/src/submodules/googletest -Subproject b007c54f2944e193ac44fba1bc997cb65826a0b +Subproject af29db7ec28d6df1c7f0f745186884091e602e0 diff --git a/src/submodules/spa-templates b/src/submodules/spa-templates -Subproject 8b90832a77eb141d957b9c484cda6f750998bb7 +Subproject 800ef5837e1a23da863001d2448df67ec31ce2a |