Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Martin Perry 2019-01-16 16:35:15 +00:00
commit ed0abe5e24
108 changed files with 2406 additions and 531 deletions

1
.github/CODEOWNERS vendored
View File

@ -3,6 +3,7 @@
/build/ @natemcmaster
/eng/ @natemcmaster
/src/Components/ @SteveSandersonMS
/src/DefaultBuilder/ @tratcher
/src/Hosting/ @tratcher
/src/Http/ @tratcher

View File

@ -102,6 +102,11 @@ param(
[Parameter(ParameterSetName = 'Groups')]
[switch]$Installers,
# By default, Windows builds will use MSBuild.exe. Passing this will force the build to run on
# dotnet.exe instead, which may cause issues if you invoke build on a project unsupported by
# MSBuild for .NET Core
[switch]$ForceCoreMsbuild,
# Other lifecycle targets
[switch]$Help, # Show help
@ -269,6 +274,9 @@ Import-Module -Force -Scope Local (Join-Path $korebuildPath 'KoreBuild.psd1')
try {
Set-KoreBuildSettings -ToolsSource $ToolsSource -DotNetHome $DotNetHome -RepoPath $RepoRoot -ConfigFile $ConfigFile -CI:$CI
if ($ForceCoreMsbuild) {
$global:KoreBuildSettings.MSBuildType = 'core'
}
Invoke-KoreBuildCommand 'default-build' @MSBuildArguments
}
finally {

View File

@ -1,130 +1,13 @@
<Project>
<PropertyGroup>
<PublishDependsOn>
GetFilesToPublish;
PublishToAzureFeed;
PublishToMyGet;
</PublishDependsOn>
</PropertyGroup>
<Target Name="Publish">
<MSBuild Projects="$(MSBuildThisFileDirectory)publish\Publish.csproj"
Targets="Restore"
Properties="$(BuildProperties);KoreBuildTasksDll=$(KoreBuildTasksDll);__DummyTarget=Restore" />
<Target Name="Publish" DependsOnTargets="$(PublishDependsOn)" />
<Target Name="GetFilesToPublish">
<ItemGroup>
<!-- Installer output files with specific metadata. -->
<_FilesToPublish Include="$(InstallersOutputPath)*.txt">
<ContentType>text/plain</ContentType>
</_FilesToPublish>
<_FilesToPublish Include="$(InstallersOutputPath)*.version">
<ContentType>text/plain</ContentType>
<CacheControl>no-cache, no-store, must-revalidate</CacheControl>
</_FilesToPublish>
<_FilesToPublish Include="$(InstallersOutputPath)*.svg">
<CacheControl>no-cache, no-store, must-revalidate</CacheControl>
<ContentType>image/svg+xml</ContentType>
</_FilesToPublish>
<!-- All other installer files. -->
<_FilesToPublish Include="$(InstallersOutputPath)*" Exclude="@(_FilesToPublish)" />
<!-- Java packages -->
<_FilesToPublish Include="$(ProductPackageOutputPath)*.jar;$(ProductPackageOutputPath)*.pom">
<BlobBasePath>aspnetcore/jar/$(PackageVersion)/</BlobBasePath>
</_FilesToPublish>
<!--
Transform the intermediate item group into the final group.
You can't use globbing _and_ set metadata using FileName and Extension at the same time. MSBuild quirks are fun.
-->
<FilesToPublish Include="@(_FilesToPublish)">
<RelativeBlobPath Condition="'%(_FilesToPublish.BlobBasePath)' != ''">%(_FilesToPublish.BlobBasePath)%(_FilesToPublish.FileName)%(_FilesToPublish.Extension)</RelativeBlobPath>
<RelativeBlobPath Condition="'%(_FilesToPublish.BlobBasePath)' == ''">aspnetcore/Runtime/$(PackageVersion)/%(_FilesToPublish.FileName)%(_FilesToPublish.Extension)</RelativeBlobPath>
</FilesToPublish>
<_FilesToPublish Remove="@(_FilesToPublish)" />
<!-- NPM packages -->
<NpmPackageToPublish Include="$(ProductPackageOutputPath)*.tgz" />
<PackageToPublish Include="$(ProductPackageOutputPath)*.symbols.nupkg" IsSymbolsPackage="true" />
<PackageToPublish Include="$(ProductPackageOutputPath)*.nupkg" Exclude="@(PackageToPublish)" />
</ItemGroup>
<!--
'Internal' packages are used to transfer bits to partner teams, and should not be used by customers.
Publishing these can be disabled.
-->
<ItemGroup Condition=" '$(PublishInternalPackages)' != 'false' ">
<PackageToPublish Include="$(InternalPackageOutputPath)*.symbols.nupkg" IsSymbolsPackage="true">
<ManifestArtifactData>NonShipping=true</ManifestArtifactData>
</PackageToPublish>
<PackageToPublish Include="$(InternalPackageOutputPath)*.nupkg" Exclude="@(PackageToPublish)">
<ManifestArtifactData>NonShipping=true</ManifestArtifactData>
</PackageToPublish>
</ItemGroup>
</Target>
<Target Name="PublishToMyGet"
DependsOnTargets="GetFilesToPublish;GetToolsets"
Condition="'$(PublishToMyget)' == 'true'">
<Error Text="Missing required property: PublishMyGetFeedUrl" Condition=" '$(PublishMyGetFeedUrl)' == '' "/>
<Error Text="Missing required property: PublishMyGetSymbolsFeedUrl" Condition=" '$(PublishMyGetSymbolsFeedUrl)' == '' "/>
<Error Text="Missing required property: PublishMyGetNpmRegistryUrl" Condition=" '$(PublishMyGetNpmRegistryUrl)' == '' "/>
<Error Text="Missing required property: PublishMyGetFeedKey" Condition=" '$(PublishMyGetFeedKey)' == '' "/>
<Error Text="No packages found to publish" Condition="@(PackageToPublish->Count()) == 0" />
<PushNuGetPackages Condition="'%(PackageToPublish.IsSymbolsPackage)' != 'true' AND @(PackageToPublish->Count()) != 0"
Packages="@(PackageToPublish)"
Feed="$(PublishMyGetFeedUrl)"
ApiKey="$(PublishMyGetFeedKey)" />
<PushNuGetPackages Condition="'%(PackageToPublish.IsSymbolsPackage)' == 'true' AND @(PackageToPublish->Count()) != 0"
Packages="@(PackageToPublish)"
Feed="$(PublishMyGetSymbolsFeedUrl)"
ApiKey="$(PublishMyGetFeedKey)" />
<PropertyGroup>
<AuthTokenSetting>$(PublishMyGetNpmRegistryUrl.Replace("https:", "")):_authToken</AuthTokenSetting>
</PropertyGroup>
<Message Condition=" @(NpmPackageToPublish->Count()) != 0 "
Text="Skipping NPM publish because there are no npm packages to publish."
Importance="high" />
<Exec Condition=" @(NpmPackageToPublish->Count()) != 0 "
Command="npm config set &quot;$(AuthTokenSetting)&quot; $(PublishMyGetFeedKey)"
StandardOutputImportance="Normal" />
<!-- When you UseCommandProcessor FileName is ignored -->
<Run Condition=" @(NpmPackageToPublish->Count()) != 0 "
FileName="cmd"
Arguments="npm;publish;--registry;$(PublishMyGetNpmRegistryUrl);%(NpmPackageToPublish.Identity)"
MaxRetries="5"
UseCommandProcessor="true"
ContinueOnError="true">
<Output TaskParameter="ExitCode" ItemName="_NpmExitCodes" />
</Run>
<Exec Condition=" @(NpmPackageToPublish->Count()) != 0 "
Command="npm config delete $(AuthTokenSetting)"
StandardOutputImportance="Normal" />
<Error Text="Publishing npm modules failed" Condition=" @(NpmPackageToPublish->Count()) != 0 AND %(_NpmExitCodes.Identity) != 0" />
</Target>
<Target Name="PublishToAzureFeed"
DependsOnTargets="GetFilesToPublish"
Condition="'$(PublishToAzureFeed)' == 'true'">
<RepoTasks.PublishToAzureBlob
AccountName="$(AzureAccountName)"
SharedAccessToken="$(AzureSharedAccessToken)"
ContainerName="$(AzureContainerName)"
Files="@(FilesToPublish)" />
<MSBuild Projects="$(MSBuildThisFileDirectory)publish\Publish.csproj"
Targets="Publish"
Properties="$(BuildProperties);KoreBuildTasksDll=$(KoreBuildTasksDll);__DummyTarget=Publish" />
</Target>
</Project>

View File

@ -11,6 +11,10 @@
<SharedFrameworkAndPackage Include="Microsoft.AspNetCore.JsonPatch" />
<SharedFrameworkAndPackage Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" />
<!-- Assemblies required by components and WebAssembly -->
<SharedFrameworkAndPackage Include="Microsoft.AspNetCore.Components" />
<SharedFrameworkAndPackage Include="Microsoft.AspNetCore.Components.Browser" />
<!-- Assemblies required by the SignalR client. -->
<SharedFrameworkAndPackage Include="Microsoft.AspNetCore.Http.Features" />
<SharedFrameworkAndPackage Include="Microsoft.AspNetCore.SignalR.Common" />

View File

@ -28,6 +28,7 @@
<ExternalDependency Include="Microsoft.Extensions.Logging.Configuration" Version="$(MicrosoftExtensionsLoggingConfigurationPackageVersion)" />
<ExternalDependency Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
<ExternalDependency Include="Microsoft.Extensions.Logging.Debug" Version="$(MicrosoftExtensionsLoggingDebugPackageVersion)" />
<ExternalDependency Include="Microsoft.JSInterop" Version="$(MicrosoftJSInteropPackageVersion)" />
<!-- Packages from aspnet/EntityFrameworkCore -->
<ExternalDependency Include="dotnet-ef" Version="$(DotNetEfPackageVersion)" />

View File

@ -0,0 +1,182 @@
<Project>
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
<PropertyGroup>
<!-- TFM doesn't matter. These settings are required to make NuGet happy so we can restore required MSBuild packages. -->
<TargetFramework>netcoreapp3.0</TargetFramework>
<DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>
<ManifestsPath>$(ArtifactsDir)manifests\</ManifestsPath>
<MaestroApiEndpoint Condition="'$(MaestroApiEndpoint)' == ''">https://maestro-prod.westus2.cloudapp.azure.com</MaestroApiEndpoint>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.DotNet.Build.Tasks.Feed" Version="2.2.0-beta.19061.6" />
<PackageReference Include="Microsoft.DotNet.Maestro.Tasks" Version="1.1.0-beta.19065.2" />
</ItemGroup>
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
<PropertyGroup>
<PublishDependsOn>
GetFilesToPublish;
GenerateBuildAssetManifest;
PublishToAzureFeed;
PublishToMyGet;
PublishToBuildAssetRegistry;
</PublishDependsOn>
</PropertyGroup>
<Target Name="Publish" DependsOnTargets="$(PublishDependsOn)" />
<Target Name="GetFilesToPublish">
<ItemGroup>
<!-- Installer output files with specific metadata. -->
<_FilesToPublish Include="$(InstallersOutputPath)*.txt">
<ContentType>text/plain</ContentType>
</_FilesToPublish>
<_FilesToPublish Include="$(InstallersOutputPath)*.version">
<ContentType>text/plain</ContentType>
<CacheControl>no-cache, no-store, must-revalidate</CacheControl>
</_FilesToPublish>
<_FilesToPublish Include="$(InstallersOutputPath)*.svg">
<CacheControl>no-cache, no-store, must-revalidate</CacheControl>
<ContentType>image/svg+xml</ContentType>
</_FilesToPublish>
<!-- All other installer files. -->
<_FilesToPublish Include="$(InstallersOutputPath)*" Exclude="@(_FilesToPublish)" />
<!-- Java packages -->
<_FilesToPublish Include="$(ProductPackageOutputPath)*.jar;$(ProductPackageOutputPath)*.pom">
<BlobBasePath>aspnetcore/jar/$(PackageVersion)/</BlobBasePath>
</_FilesToPublish>
<!-- NPM packages -->
<NpmPackageToPublish Include="$(ProductPackageOutputPath)*.tgz">
<BlobBasePath>aspnetcore/npm/$(PackageVersion)/</BlobBasePath>
</NpmPackageToPublish>
<_FilesToPublish Include="@(NpmPackageToPublish)" />
<!--
Transform the intermediate item group into the final group.
You can't use globbing _and_ set metadata using FileName and Extension at the same time. MSBuild quirks are fun.
-->
<FilesToPublish Include="@(_FilesToPublish)">
<RelativeBlobPath Condition="'%(_FilesToPublish.BlobBasePath)' != ''">%(_FilesToPublish.BlobBasePath)%(_FilesToPublish.FileName)%(_FilesToPublish.Extension)</RelativeBlobPath>
<RelativeBlobPath Condition="'%(_FilesToPublish.BlobBasePath)' == ''">aspnetcore/Runtime/$(PackageVersion)/%(_FilesToPublish.FileName)%(_FilesToPublish.Extension)</RelativeBlobPath>
</FilesToPublish>
<_FilesToPublish Remove="@(_FilesToPublish)" />
<PackageToPublish Include="$(ProductPackageOutputPath)*.symbols.nupkg" IsSymbolsPackage="true" />
<PackageToPublish Include="$(ProductPackageOutputPath)*.nupkg" Exclude="@(PackageToPublish)" />
</ItemGroup>
<!--
'Internal' packages are used to transfer bits to partner teams, and should not be used by customers.
Publishing these can be disabled.
-->
<ItemGroup Condition=" '$(PublishInternalPackages)' != 'false' ">
<PackageToPublish Include="$(InternalPackageOutputPath)*.symbols.nupkg" IsSymbolsPackage="true">
<ManifestArtifactData>NonShipping=true</ManifestArtifactData>
</PackageToPublish>
<PackageToPublish Include="$(InternalPackageOutputPath)*.nupkg" Exclude="@(PackageToPublish)">
<ManifestArtifactData>NonShipping=true</ManifestArtifactData>
</PackageToPublish>
</ItemGroup>
<Error Text="Missing required metadata 'RelativeBlobPath' for FilesToPublish: @(FilesToPublish)" Condition="'@(FilesToPublish)' != '' AND '%(RelativeBlobPath)' == ''" />
</Target>
<UsingTask TaskName="KoreBuild.Tasks.PushNuGetPackages" AssemblyFile="$(KoreBuildTasksDll)" />
<Target Name="PublishToMyGet"
DependsOnTargets="GetFilesToPublish"
Condition="'$(PublishToMyget)' == 'true'">
<Error Text="Missing required property: PublishMyGetFeedUrl" Condition=" '$(PublishMyGetFeedUrl)' == '' "/>
<Error Text="Missing required property: PublishMyGetSymbolsFeedUrl" Condition=" '$(PublishMyGetSymbolsFeedUrl)' == '' "/>
<Error Text="Missing required property: PublishMyGetNpmRegistryUrl" Condition=" '$(PublishMyGetNpmRegistryUrl)' == '' "/>
<Error Text="Missing required property: PublishMyGetFeedKey" Condition=" '$(PublishMyGetFeedKey)' == '' "/>
<Error Text="No packages found to publish" Condition="@(PackageToPublish->Count()) == 0" />
<PushNuGetPackages Condition="'%(PackageToPublish.IsSymbolsPackage)' != 'true' AND @(PackageToPublish->Count()) != 0"
Packages="@(PackageToPublish)"
TimeoutSeconds="300"
Feed="$(PublishMyGetFeedUrl)"
ApiKey="$(PublishMyGetFeedKey)" />
<PushNuGetPackages Condition="'%(PackageToPublish.IsSymbolsPackage)' == 'true' AND @(PackageToPublish->Count()) != 0"
Packages="@(PackageToPublish)"
TimeoutSeconds="300"
Feed="$(PublishMyGetSymbolsFeedUrl)"
ApiKey="$(PublishMyGetFeedKey)" />
<PropertyGroup>
<AuthTokenSetting>$(PublishMyGetNpmRegistryUrl.Replace("https:", "")):_authToken</AuthTokenSetting>
</PropertyGroup>
<Message Condition=" @(NpmPackageToPublish->Count()) != 0 "
Text="Skipping NPM publish because there are no npm packages to publish."
Importance="high" />
<Exec Condition=" @(NpmPackageToPublish->Count()) != 0 "
Command="npm config set &quot;$(AuthTokenSetting)&quot; $(PublishMyGetFeedKey)"
StandardOutputImportance="Normal" />
<Exec Condition=" @(NpmPackageToPublish->Count()) != 0 "
Command="npm publish --registry &quot;$(PublishMyGetNpmRegistryUrl)&quot; &quot;%(NpmPackageToPublish.Identity)&quot;"
ContinueOnError="true">
<Output TaskParameter="ExitCode" ItemName="_NpmExitCodes" />
</Exec>
<Exec Condition=" @(NpmPackageToPublish->Count()) != 0 "
Command="npm config delete $(AuthTokenSetting)"
StandardOutputImportance="Normal" />
<Error Text="Publishing npm modules failed" Condition=" @(NpmPackageToPublish->Count()) != 0 AND %(_NpmExitCodes.Identity) != 0" />
</Target>
<Target Name="PublishToAzureFeed"
DependsOnTargets="GetFilesToPublish"
Condition="'$(PublishToAzureFeed)' == 'true'">
<RepoTasks.PublishToAzureBlob
AccountName="$(AzureAccountName)"
SharedAccessToken="$(AzureSharedAccessToken)"
ContainerName="$(AzureContainerName)"
Files="@(FilesToPublish)" />
</Target>
<Target Name="GenerateBuildAssetManifest"
DependsOnTargets="GetFilesToPublish;ResolveRepositoryBranch;ResolveCommitHash">
<GenerateBuildManifest
Artifacts="@(PackageToPublish);@(FilesToPublish)"
OutputPath="$(ManifestsPath)aspnetcore-$(SharedFxRid)-$(PackageVersion).xml"
BuildId="$(PackageVersion)"
BuildData="Location=https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json"
RepoUri="$(RepositoryUrl)"
RepoBranch="$(RepositoryBranch)"
RepoCommit="$(RepositoryCommit)" />
</Target>
<UsingTask TaskName="PushMetadataToBuildAssetRegistry" AssemblyFile="$(PkgMicrosoft_DotNet_Maestro_Tasks)\tools\netcoreapp2.1\Microsoft.DotNet.Maestro.Tasks.dll"/>
<Target Name="PublishToBuildAssetRegistry"
DependsOnTargets="GenerateBuildAssetManifest"
Condition="'$(PublishToBuildAssetRegistry)' == 'true'">
<Error Text="Missing required property: MaestroApiEndpoint" Condition=" '$(MaestroApiEndpoint)' == '' "/>
<Error Text="Missing required property: BuildAssetRegistryToken" Condition=" '$(BuildAssetRegistryToken)' == '' "/>
<PushMetadataToBuildAssetRegistry
ManifestsPath="$(ManifestsPath)"
BuildAssetRegistryToken="$(BuildAssetRegistryToken)"
MaestroApiEndpoint="$(MaestroApiEndpoint)" />
</Target>
</Project>

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if BUILD_AZ_TASKS
using System;
using System.Collections.Generic;
using System.IO;
@ -142,3 +143,4 @@ namespace RepoTasks
}
}
}
#endif

View File

@ -5,13 +5,14 @@
<TargetFramework Condition="'$(MSBuildRuntimeType)' == 'Core' ">netcoreapp2.2</TargetFramework>
<TargetFramework Condition="'$(MSBuildRuntimeType)' != 'Core' ">net461</TargetFramework>
<DefineConstants Condition="'$(BuildWindowsInstallers)' == 'true'">$(DefineConstants);BUILD_MSI_TASKS</DefineConstants>
<DefineConstants Condition="'$(PublishToAzureFeed)' == 'true'">$(DefineConstants);BUILD_AZ_TASKS</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Remove="Internal.AspNetCore.Sdk" />
<PackageReference Include="NuGet.Build.Tasks" Version="4.9.1" />
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="2.1.0" />
<PackageReference Include="WindowsAzure.Storage" Version="8.7.0" />
<PackageReference Include="WindowsAzure.Storage" Version="8.7.0" Condition="'$(PublishToAzureFeed)' == 'true'" />
</ItemGroup>
<ItemGroup Condition="'$(BuildWindowsInstallers)' == 'true'">

View File

@ -9,6 +9,6 @@
<UsingTask TaskName="RepoTasks.JoinRepoItems" AssemblyFile="$(_RepoTaskAssembly)" />
<UsingTask TaskName="RepoTasks.OrderBy" AssemblyFile="$(_RepoTaskAssembly)" />
<UsingTask TaskName="RepoTasks.GenerateSharedFrameworkMetadataFiles" AssemblyFile="$(_RepoTaskAssembly)" />
<UsingTask TaskName="RepoTasks.PublishToAzureBlob" AssemblyFile="$(_RepoTaskAssembly)" />
<UsingTask TaskName="RepoTasks.PublishToAzureBlob" AssemblyFile="$(_RepoTaskAssembly)" Condition="'$(PublishToAzureFeed)' == 'true'" />
<UsingTask TaskName="RepoTasks.RemoveSharedFrameworkDependencies" AssemblyFile="$(_RepoTaskAssembly)" />
</Project>

View File

@ -37,227 +37,231 @@
<Uri>https://github.com/aspnet/EntityFrameworkCore</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.AspNetCore.Analyzer.Testing" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.AspNetCore.Analyzer.Testing" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.AspNetCore.BenchmarkRunner.Sources" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.AspNetCore.BenchmarkRunner.Sources" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.ActivatorUtilities.Sources" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.ActivatorUtilities.Sources" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Caching.Abstractions" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Caching.Abstractions" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Caching.Memory" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Caching.Memory" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Caching.SqlServer" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Caching.SqlServer" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Caching.StackExchangeRedis" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Caching.StackExchangeRedis" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.CommandLineUtils.Sources" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.CommandLineUtils.Sources" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration.Abstractions" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Configuration.Abstractions" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration.Binder" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Configuration.Binder" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration.CommandLine" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Configuration.CommandLine" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration.FileExtensions" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Configuration.FileExtensions" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration.Ini" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Configuration.Ini" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration.Json" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Configuration.Json" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration.KeyPerFile" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Configuration.KeyPerFile" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration.UserSecrets" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Configuration.UserSecrets" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration.Xml" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Configuration.Xml" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Configuration" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.DependencyInjection.Specification.Tests" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.DependencyInjection.Specification.Tests" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.DependencyInjection" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.DependencyInjection" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.DiagnosticAdapter" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.DiagnosticAdapter" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Diagnostics.HealthChecks" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Diagnostics.HealthChecks" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.FileProviders.Abstractions" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.FileProviders.Abstractions" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.FileProviders.Composite" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.FileProviders.Composite" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.FileProviders.Embedded" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.FileProviders.Embedded" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.FileProviders.Physical" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.FileProviders.Physical" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.FileSystemGlobbing" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.FileSystemGlobbing" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.HashCodeCombiner.Sources" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.HashCodeCombiner.Sources" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Hosting.Abstractions" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Hosting.Abstractions" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Hosting" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Hosting" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.HostFactoryResolver.Sources" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.HostFactoryResolver.Sources" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Http" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Http" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Localization.Abstractions" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Localization.Abstractions" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Localization" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Localization" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Logging.Abstractions" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Logging.Abstractions" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Logging.AzureAppServices" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Logging.AzureAppServices" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Logging.Configuration" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Logging.Configuration" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Logging.Console" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Logging.Console" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Logging.Debug" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Logging.Debug" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Logging.EventSource" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Logging.EventSource" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Logging.TraceSource" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Logging.TraceSource" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Logging.Testing" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Logging.Testing" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Logging" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Logging" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.ObjectPool" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.ObjectPool" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Options.DataAnnotations" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Options.DataAnnotations" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Options" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Options" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.ParameterDefaultValue.Sources" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.ParameterDefaultValue.Sources" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Primitives" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.Primitives" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.TypeNameHelper.Sources" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.TypeNameHelper.Sources" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.ValueStopWatch.Sources" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.ValueStopWatch.Sources" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.WebEncoders" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.Extensions.WebEncoders" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.JSInterop" Version="3.0.0-preview.19059.5">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
@ -355,11 +359,11 @@
</Dependency>
</ProductDependencies>
<ToolsetDependencies>
<Dependency Name="Internal.AspNetCore.Analyzers" Version="3.0.0-preview.19059.4">
<Dependency Name="Internal.AspNetCore.Analyzers" Version="3.0.0-preview.19065.2">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>
<Dependency Name="Microsoft.AspNetCore.Testing" Version="3.0.0-preview.19059.4">
<Dependency Name="Microsoft.AspNetCore.Testing" Version="3.0.0-preview.19065.2">
<Uri>https://github.com/aspnet/Extensions</Uri>
<Sha>000000</Sha>
</Dependency>

View File

@ -35,64 +35,65 @@
<SystemThreadingChannelsPackageVersion>4.6.0-preview.18619.1</SystemThreadingChannelsPackageVersion>
<!-- Packages from aspnet/Extensions -->
<InternalAspNetCoreAnalyzersPackageVersion>3.0.0-preview.19059.4</InternalAspNetCoreAnalyzersPackageVersion>
<MicrosoftAspNetCoreAnalyzerTestingPackageVersion>3.0.0-preview.19059.4</MicrosoftAspNetCoreAnalyzerTestingPackageVersion>
<MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>3.0.0-preview.19059.4</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>
<MicrosoftAspNetCoreTestingPackageVersion>3.0.0-preview.19059.4</MicrosoftAspNetCoreTestingPackageVersion>
<MicrosoftExtensionsActivatorUtilitiesSourcesPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsActivatorUtilitiesSourcesPackageVersion>
<MicrosoftExtensionsCachingAbstractionsPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsCachingAbstractionsPackageVersion>
<MicrosoftExtensionsCachingMemoryPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsCachingMemoryPackageVersion>
<MicrosoftExtensionsCachingSqlServerPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsCachingSqlServerPackageVersion>
<MicrosoftExtensionsCachingStackExchangeRedisPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsCachingStackExchangeRedisPackageVersion>
<MicrosoftExtensionsCommandLineUtilsSourcesPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsCommandLineUtilsSourcesPackageVersion>
<MicrosoftExtensionsConfigurationAbstractionsPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsConfigurationAbstractionsPackageVersion>
<MicrosoftExtensionsConfigurationAzureKeyVaultPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsConfigurationAzureKeyVaultPackageVersion>
<MicrosoftExtensionsConfigurationBinderPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsConfigurationBinderPackageVersion>
<MicrosoftExtensionsConfigurationCommandLinePackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsConfigurationCommandLinePackageVersion>
<MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>
<MicrosoftExtensionsConfigurationFileExtensionsPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsConfigurationFileExtensionsPackageVersion>
<MicrosoftExtensionsConfigurationIniPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsConfigurationIniPackageVersion>
<MicrosoftExtensionsConfigurationJsonPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsConfigurationJsonPackageVersion>
<MicrosoftExtensionsConfigurationKeyPerFilePackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsConfigurationKeyPerFilePackageVersion>
<MicrosoftExtensionsConfigurationPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsConfigurationPackageVersion>
<MicrosoftExtensionsConfigurationUserSecretsPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsConfigurationUserSecretsPackageVersion>
<MicrosoftExtensionsConfigurationXmlPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsConfigurationXmlPackageVersion>
<MicrosoftExtensionsDependencyInjectionAbstractionsPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsDependencyInjectionAbstractionsPackageVersion>
<MicrosoftExtensionsDependencyInjectionPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsDependencyInjectionPackageVersion>
<MicrosoftExtensionsDependencyInjectionSpecificationTestsPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsDependencyInjectionSpecificationTestsPackageVersion>
<MicrosoftExtensionsDiagnosticAdapterPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsDiagnosticAdapterPackageVersion>
<MicrosoftExtensionsDiagnosticsHealthChecksAbstractionsPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsDiagnosticsHealthChecksAbstractionsPackageVersion>
<MicrosoftExtensionsDiagnosticsHealthChecksPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsDiagnosticsHealthChecksPackageVersion>
<MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>
<MicrosoftExtensionsFileProvidersCompositePackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsFileProvidersCompositePackageVersion>
<MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>
<MicrosoftExtensionsFileProvidersPhysicalPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsFileProvidersPhysicalPackageVersion>
<MicrosoftExtensionsFileSystemGlobbingPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsFileSystemGlobbingPackageVersion>
<MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion>
<MicrosoftExtensionsHostingAbstractionsPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsHostingAbstractionsPackageVersion>
<MicrosoftExtensionsHostingPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsHostingPackageVersion>
<MicrosoftExtensionsHostFactoryResolverSourcesPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsHostFactoryResolverSourcesPackageVersion>
<MicrosoftExtensionsHttpPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsHttpPackageVersion>
<MicrosoftExtensionsLocalizationAbstractionsPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsLocalizationAbstractionsPackageVersion>
<MicrosoftExtensionsLocalizationPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsLocalizationPackageVersion>
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
<MicrosoftExtensionsLoggingAzureAppServicesPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsLoggingAzureAppServicesPackageVersion>
<MicrosoftExtensionsLoggingConfigurationPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsLoggingConfigurationPackageVersion>
<MicrosoftExtensionsLoggingConsolePackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsLoggingConsolePackageVersion>
<MicrosoftExtensionsLoggingDebugPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsLoggingDebugPackageVersion>
<MicrosoftExtensionsLoggingEventSourcePackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsLoggingEventSourcePackageVersion>
<MicrosoftExtensionsLoggingPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsLoggingPackageVersion>
<MicrosoftExtensionsLoggingTestingPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsLoggingTestingPackageVersion>
<MicrosoftExtensionsLoggingTraceSourcePackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsLoggingTraceSourcePackageVersion>
<MicrosoftExtensionsObjectPoolPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsObjectPoolPackageVersion>
<MicrosoftExtensionsOptionsConfigurationExtensionsPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsOptionsConfigurationExtensionsPackageVersion>
<MicrosoftExtensionsOptionsDataAnnotationsPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsOptionsDataAnnotationsPackageVersion>
<MicrosoftExtensionsOptionsPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsOptionsPackageVersion>
<MicrosoftExtensionsParameterDefaultValueSourcesPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsParameterDefaultValueSourcesPackageVersion>
<MicrosoftExtensionsPrimitivesPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsPrimitivesPackageVersion>
<MicrosoftExtensionsTypeNameHelperSourcesPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsTypeNameHelperSourcesPackageVersion>
<MicrosoftExtensionsValueStopwatchSourcesPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsValueStopwatchSourcesPackageVersion>
<MicrosoftExtensionsWebEncodersPackageVersion>3.0.0-preview.19059.4</MicrosoftExtensionsWebEncodersPackageVersion>
<InternalAspNetCoreAnalyzersPackageVersion>3.0.0-preview.19059.5</InternalAspNetCoreAnalyzersPackageVersion>
<MicrosoftAspNetCoreAnalyzerTestingPackageVersion>3.0.0-preview.19059.5</MicrosoftAspNetCoreAnalyzerTestingPackageVersion>
<MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>3.0.0-preview.19059.5</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>
<MicrosoftAspNetCoreTestingPackageVersion>3.0.0-preview.19059.5</MicrosoftAspNetCoreTestingPackageVersion>
<MicrosoftExtensionsActivatorUtilitiesSourcesPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsActivatorUtilitiesSourcesPackageVersion>
<MicrosoftExtensionsCachingAbstractionsPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsCachingAbstractionsPackageVersion>
<MicrosoftExtensionsCachingMemoryPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsCachingMemoryPackageVersion>
<MicrosoftExtensionsCachingSqlServerPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsCachingSqlServerPackageVersion>
<MicrosoftExtensionsCachingStackExchangeRedisPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsCachingStackExchangeRedisPackageVersion>
<MicrosoftExtensionsCommandLineUtilsSourcesPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsCommandLineUtilsSourcesPackageVersion>
<MicrosoftExtensionsConfigurationAbstractionsPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsConfigurationAbstractionsPackageVersion>
<MicrosoftExtensionsConfigurationAzureKeyVaultPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsConfigurationAzureKeyVaultPackageVersion>
<MicrosoftExtensionsConfigurationBinderPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsConfigurationBinderPackageVersion>
<MicrosoftExtensionsConfigurationCommandLinePackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsConfigurationCommandLinePackageVersion>
<MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>
<MicrosoftExtensionsConfigurationFileExtensionsPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsConfigurationFileExtensionsPackageVersion>
<MicrosoftExtensionsConfigurationIniPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsConfigurationIniPackageVersion>
<MicrosoftExtensionsConfigurationJsonPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsConfigurationJsonPackageVersion>
<MicrosoftExtensionsConfigurationKeyPerFilePackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsConfigurationKeyPerFilePackageVersion>
<MicrosoftExtensionsConfigurationPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsConfigurationPackageVersion>
<MicrosoftExtensionsConfigurationUserSecretsPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsConfigurationUserSecretsPackageVersion>
<MicrosoftExtensionsConfigurationXmlPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsConfigurationXmlPackageVersion>
<MicrosoftExtensionsDependencyInjectionAbstractionsPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsDependencyInjectionAbstractionsPackageVersion>
<MicrosoftExtensionsDependencyInjectionPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsDependencyInjectionPackageVersion>
<MicrosoftExtensionsDependencyInjectionSpecificationTestsPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsDependencyInjectionSpecificationTestsPackageVersion>
<MicrosoftExtensionsDiagnosticAdapterPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsDiagnosticAdapterPackageVersion>
<MicrosoftExtensionsDiagnosticsHealthChecksAbstractionsPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsDiagnosticsHealthChecksAbstractionsPackageVersion>
<MicrosoftExtensionsDiagnosticsHealthChecksPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsDiagnosticsHealthChecksPackageVersion>
<MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>
<MicrosoftExtensionsFileProvidersCompositePackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsFileProvidersCompositePackageVersion>
<MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>
<MicrosoftExtensionsFileProvidersPhysicalPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsFileProvidersPhysicalPackageVersion>
<MicrosoftExtensionsFileSystemGlobbingPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsFileSystemGlobbingPackageVersion>
<MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion>
<MicrosoftExtensionsHostingAbstractionsPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsHostingAbstractionsPackageVersion>
<MicrosoftExtensionsHostingPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsHostingPackageVersion>
<MicrosoftExtensionsHostFactoryResolverSourcesPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsHostFactoryResolverSourcesPackageVersion>
<MicrosoftExtensionsHttpPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsHttpPackageVersion>
<MicrosoftExtensionsLocalizationAbstractionsPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsLocalizationAbstractionsPackageVersion>
<MicrosoftExtensionsLocalizationPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsLocalizationPackageVersion>
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
<MicrosoftExtensionsLoggingAzureAppServicesPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsLoggingAzureAppServicesPackageVersion>
<MicrosoftExtensionsLoggingConfigurationPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsLoggingConfigurationPackageVersion>
<MicrosoftExtensionsLoggingConsolePackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsLoggingConsolePackageVersion>
<MicrosoftExtensionsLoggingDebugPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsLoggingDebugPackageVersion>
<MicrosoftExtensionsLoggingEventSourcePackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsLoggingEventSourcePackageVersion>
<MicrosoftExtensionsLoggingPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsLoggingPackageVersion>
<MicrosoftExtensionsLoggingTestingPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsLoggingTestingPackageVersion>
<MicrosoftExtensionsLoggingTraceSourcePackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsLoggingTraceSourcePackageVersion>
<MicrosoftExtensionsObjectPoolPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsObjectPoolPackageVersion>
<MicrosoftExtensionsOptionsConfigurationExtensionsPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsOptionsConfigurationExtensionsPackageVersion>
<MicrosoftExtensionsOptionsDataAnnotationsPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsOptionsDataAnnotationsPackageVersion>
<MicrosoftExtensionsOptionsPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsOptionsPackageVersion>
<MicrosoftExtensionsParameterDefaultValueSourcesPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsParameterDefaultValueSourcesPackageVersion>
<MicrosoftExtensionsPrimitivesPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsPrimitivesPackageVersion>
<MicrosoftExtensionsTypeNameHelperSourcesPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsTypeNameHelperSourcesPackageVersion>
<MicrosoftExtensionsValueStopwatchSourcesPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsValueStopwatchSourcesPackageVersion>
<MicrosoftExtensionsWebEncodersPackageVersion>3.0.0-preview.19059.5</MicrosoftExtensionsWebEncodersPackageVersion>
<MicrosoftJSInteropPackageVersion>3.0.0-preview.19059.5</MicrosoftJSInteropPackageVersion>
<!-- Packages from aspnet/EntityFrameworkCore -->
<DotNetEfPackageVersion>3.0.0-preview.18604.3</DotNetEfPackageVersion>
@ -105,7 +106,7 @@
<MicrosoftEntityFrameworkCorePackageVersion>3.0.0-preview.18604.3</MicrosoftEntityFrameworkCorePackageVersion>
<!-- Packages from aspnet/AspNetCore-Tooling -->
<MicrosoftNETSdkRazorPackageVersion>3.0.0-preview-19057-06</MicrosoftNETSdkRazorPackageVersion>
<MicrosoftNETSdkRazorPackageVersion>3.0.0-preview-19064-09</MicrosoftNETSdkRazorPackageVersion>
</PropertyGroup>
<PropertyGroup Label="Build tool dependencies">

View File

@ -73,6 +73,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.TestHo
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authorization", "..\Security\Authorization\Core\src\Microsoft.AspNetCore.Authorization.csproj", "{C57DFBC2-A887-44B4-A149-7ABFA6D98F7E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.OpenIdConnect", "..\Security\Authentication\OpenIdConnect\src\Microsoft.AspNetCore.Authentication.OpenIdConnect.csproj", "{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.OAuth", "..\Security\Authentication\OAuth\src\Microsoft.AspNetCore.Authentication.OAuth.csproj", "{406DF28A-0B58-408E-96B0-2D373EE36352}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication", "..\Security\Authentication\Core\src\Microsoft.AspNetCore.Authentication.csproj", "{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -383,6 +389,42 @@ Global
{C57DFBC2-A887-44B4-A149-7ABFA6D98F7E}.Release|x64.Build.0 = Release|Any CPU
{C57DFBC2-A887-44B4-A149-7ABFA6D98F7E}.Release|x86.ActiveCfg = Release|Any CPU
{C57DFBC2-A887-44B4-A149-7ABFA6D98F7E}.Release|x86.Build.0 = Release|Any CPU
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}.Debug|x64.ActiveCfg = Debug|Any CPU
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}.Debug|x64.Build.0 = Debug|Any CPU
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}.Debug|x86.ActiveCfg = Debug|Any CPU
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}.Debug|x86.Build.0 = Debug|Any CPU
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}.Release|Any CPU.Build.0 = Release|Any CPU
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}.Release|x64.ActiveCfg = Release|Any CPU
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}.Release|x64.Build.0 = Release|Any CPU
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}.Release|x86.ActiveCfg = Release|Any CPU
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C}.Release|x86.Build.0 = Release|Any CPU
{406DF28A-0B58-408E-96B0-2D373EE36352}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{406DF28A-0B58-408E-96B0-2D373EE36352}.Debug|Any CPU.Build.0 = Debug|Any CPU
{406DF28A-0B58-408E-96B0-2D373EE36352}.Debug|x64.ActiveCfg = Debug|Any CPU
{406DF28A-0B58-408E-96B0-2D373EE36352}.Debug|x64.Build.0 = Debug|Any CPU
{406DF28A-0B58-408E-96B0-2D373EE36352}.Debug|x86.ActiveCfg = Debug|Any CPU
{406DF28A-0B58-408E-96B0-2D373EE36352}.Debug|x86.Build.0 = Debug|Any CPU
{406DF28A-0B58-408E-96B0-2D373EE36352}.Release|Any CPU.ActiveCfg = Release|Any CPU
{406DF28A-0B58-408E-96B0-2D373EE36352}.Release|Any CPU.Build.0 = Release|Any CPU
{406DF28A-0B58-408E-96B0-2D373EE36352}.Release|x64.ActiveCfg = Release|Any CPU
{406DF28A-0B58-408E-96B0-2D373EE36352}.Release|x64.Build.0 = Release|Any CPU
{406DF28A-0B58-408E-96B0-2D373EE36352}.Release|x86.ActiveCfg = Release|Any CPU
{406DF28A-0B58-408E-96B0-2D373EE36352}.Release|x86.Build.0 = Release|Any CPU
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}.Debug|x64.ActiveCfg = Debug|Any CPU
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}.Debug|x64.Build.0 = Debug|Any CPU
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}.Debug|x86.ActiveCfg = Debug|Any CPU
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}.Debug|x86.Build.0 = Debug|Any CPU
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}.Release|Any CPU.Build.0 = Release|Any CPU
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}.Release|x64.ActiveCfg = Release|Any CPU
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}.Release|x64.Build.0 = Release|Any CPU
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}.Release|x86.ActiveCfg = Release|Any CPU
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -418,6 +460,9 @@ Global
{38027842-48A7-4A64-A44F-004BAF0AB450} = {84622717-F98A-4DE2-806E-1EF89C45C0EB}
{C520D48E-87A0-463D-B4CF-3E6B68F8F4D0} = {84622717-F98A-4DE2-806E-1EF89C45C0EB}
{C57DFBC2-A887-44B4-A149-7ABFA6D98F7E} = {84622717-F98A-4DE2-806E-1EF89C45C0EB}
{F44054A2-DAC9-467F-B899-F35F9DCDAE9C} = {84622717-F98A-4DE2-806E-1EF89C45C0EB}
{406DF28A-0B58-408E-96B0-2D373EE36352} = {84622717-F98A-4DE2-806E-1EF89C45C0EB}
{A5E7BA46-B76B-467A-88FA-38E04D0A42FC} = {84622717-F98A-4DE2-806E-1EF89C45C0EB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {81AADD49-473B-43ED-8A08-F6B7A058AA39}

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.using Microsoft.AspNetCore.Authorization;
using System.Net;
@ -11,7 +11,9 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.AspNetCore.TestHost;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Primitives;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Xunit;
@ -158,5 +160,60 @@ namespace Microsoft.AspNetCore.Authentication.AzureAD.FunctionalTests
// Assert
Assert.Equal(expectedStatusCode, response.StatusCode);
}
[Fact]
public async Task ADB2C_EndToEnd_PasswordReset()
{
var client = Factory.WithWebHostBuilder(builder => builder.ConfigureTestServices(
services =>
{
services
.AddAuthentication(AzureADB2CDefaults.AuthenticationScheme)
.AddAzureADB2C(o =>
{
o.Instance = "https://login.microsoftonline.com/tfp/";
o.ClientId = "ClientId";
o.CallbackPath = "/signin-oidc";
o.Domain = "test.onmicrosoft.com";
o.SignUpSignInPolicyId = "B2C_1_SiUpIn";
o.ResetPasswordPolicyId = "B2C_1_SSPR";
o.EditProfilePolicyId = "B2C_1_SiPe";
});
services.Configure<OpenIdConnectOptions>(AzureADB2CDefaults.OpenIdScheme, o =>
{
o.Configuration = new OpenIdConnectConfiguration()
{
Issuer = "https://www.example.com",
TokenEndpoint = "https://www.example.com/token",
AuthorizationEndpoint = "https://www.example.com/authorize",
EndSessionEndpoint = "https://www.example.com/logout"
};
// CookieContainer doesn't allow cookies from other paths
o.CorrelationCookie.Path = "/";
o.NonceCookie.Path = "/";
});
services.AddMvc(o => o.Filters.Add(
new AuthorizeFilter(new AuthorizationPolicyBuilder(new[] { AzureADB2CDefaults.AuthenticationScheme })
.RequireAuthenticatedUser().Build())));
})).CreateClient(new WebApplicationFactoryClientOptions() { AllowAutoRedirect = false });
var response = await client.GetAsync("/api/get");
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
var location = response.Headers.Location;
Assert.StartsWith("https://www.example.com/authorize", location.AbsoluteUri);
var queryString = location.Query;
var query = QueryHelpers.ParseQuery(queryString);
var state = query["state"];
Assert.False(StringValues.IsNullOrEmpty(state));
// Mock Authorization response
response = await client.GetAsync($"/signin-oidc?error=access_denied&error_description=AADB2C90118&state={state}");
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
Assert.Equal("/AzureADB2C/Account/ResetPassword/AzureADB2C", response.Headers.Location.OriginalString);
}
}
}

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
@ -9,16 +9,8 @@
<Reference Include="Microsoft.AspNetCore.Authentication.AzureADB2C.UI" />
<Reference Include="Microsoft.AspNetCore.Authorization" />
<Reference Include="Microsoft.AspNetCore.DataProtection.Extensions" />
<Reference Include="Microsoft.AspNetCore.Hosting" />
<Reference Include="Microsoft.AspNetCore" />
<Reference Include="Microsoft.AspNetCore.Mvc" />
<Reference Include="Microsoft.AspNetCore.Server.IISIntegration" />
<Reference Include="Microsoft.AspNetCore.Server.Kestrel" />
<Reference Include="Microsoft.Extensions.Configuration.CommandLine" />
<Reference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" />
<Reference Include="Microsoft.Extensions.Configuration.UserSecrets" />
<Reference Include="Microsoft.Extensions.Logging.Configuration" />
<Reference Include="Microsoft.Extensions.Logging.Console" />
<Reference Include="Microsoft.Extensions.Logging.Debug" />
<Reference Include="Microsoft.NET.Sdk.Razor" PrivateAssets="All" />
</ItemGroup>

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
@ -23,55 +23,8 @@ namespace AzureAD.WebSite
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
var builder = new WebHostBuilder()
.UseKestrel((builderContext, options) =>
{
options.Configure(builderContext.Configuration.GetSection("Kestrel"));
})
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, config) =>
{
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
if (env.IsDevelopment())
{
var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
if (appAssembly != null)
{
config.AddUserSecrets(appAssembly, optional: true);
}
}
config.AddEnvironmentVariables();
if (args != null)
{
config.AddCommandLine(args);
}
})
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
logging.AddConsole();
logging.AddDebug();
})
.UseIISIntegration()
.UseDefaultServiceProvider((context, options) =>
{
options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
});
if (args != null)
{
builder.UseConfiguration(new ConfigurationBuilder().AddCommandLine(args).Build());
}
builder.UseStartup<Startup>();
return builder;
return WebHost.CreateDefaultBuilder()
.UseStartup<Startup>();
}
}
}

View File

@ -25,3 +25,31 @@ indent_size = 2
[*.{xml,csproj,config,*proj,targets,props}]
indent_size = 2
# Dotnet code style settings:
[*.cs]
# Sort using and Import directives with System.* appearing first
dotnet_sort_system_directives_first = true
# Don't use this. qualifier
dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_property = false:suggestion
# use int x = .. over Int32
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
# use int.MaxValue over Int32.MaxValue
dotnet_style_predefined_type_for_member_access = true:suggestion
# Require var all the time.
csharp_style_var_for_built_in_types = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
csharp_style_var_elsewhere = true:suggestion
# Newline settings
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true

View File

@ -22,6 +22,9 @@
<SignedPackageFile Include="Microsoft.AspNetCore.Components.Browser.JS.dll" Certificate="$(AssemblySigningCertName)" />
<SignedPackageFile Include="Microsoft.AspNetCore.Blazor.Build.exe" Certificate="$(AssemblySigningCertName)" />
<!-- 1st party assembly we redistribute (part of the CLI tool) -->
<SignedPackageFile Include="Microsoft.JSInterop.dll" Certificate="$(AssemblySigningCertName)" />
<!-- 3rd party assemblies we redistribute. -->
<SignedPackageFile Include="AngleSharp.dll" Certificate="$(AssemblySigning3rdPartyCertName)" />
<SignedPackageFile Include="Mono.Cecil.dll" Certificate="$(AssemblySigning3rdPartyCertName)" />
@ -37,7 +40,6 @@
<ExcludePackageFileFromSigning Include="Microsoft.Extensions.FileProviders.Physical.dll" />
<ExcludePackageFileFromSigning Include="Microsoft.Extensions.FileSystemGlobbing.dll" />
<ExcludePackageFileFromSigning Include="Microsoft.Extensions.Primitives.dll" />
<ExcludePackageFileFromSigning Include="Microsoft.JSInterop.dll" />
<ExcludePackageFileFromSigning Include="System.CodeDom.dll" />
<ExcludePackageFileFromSigning Include="System.Runtime.CompilerServices.Unsafe.dll" />
<ExcludePackageFileFromSigning Include="System.Text.Encoding.CodePages.dll" />

View File

@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Mono.WebAssembly.Interop" Version="$(JSInteropPackageVersion)" />
<PackageReference Include="Mono.WebAssembly.Interop" Version="$(MonoWebAssemblyInteropPackageVersion)" />
</ItemGroup>
<ItemGroup>

View File

@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Blazor.Rendering
/// Provides mechanisms for rendering <see cref="IComponent"/> instances in a
/// web browser, dispatching events to them, and refreshing the UI as required.
/// </summary>
public class WebAssemblyRenderer : Renderer, IDisposable
public class WebAssemblyRenderer : Renderer
{
private readonly int _webAssemblyRendererId;
@ -71,11 +71,10 @@ namespace Microsoft.AspNetCore.Blazor.Rendering
RenderRootComponent(componentId);
}
/// <summary>
/// Disposes the instance.
/// </summary>
public void Dispose()
/// <inheritdoc />
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
RendererRegistry.Current.TryRemove(_webAssemblyRendererId);
}

View File

@ -12,7 +12,7 @@
<MicrosoftAspNetCoreHtmlAbstractionsPackageVersion>3.0.0-alpha1-10605</MicrosoftAspNetCoreHtmlAbstractionsPackageVersion>
<MicrosoftAspNetCoreRazorDesignPackageVersion>3.0.0-alpha1-10605</MicrosoftAspNetCoreRazorDesignPackageVersion>
<MicrosoftExtensionsDependencyInjectionPackageVersion>3.0.0-alpha1-10605</MicrosoftExtensionsDependencyInjectionPackageVersion>
<MicrosoftNETSdkRazorPackageVersion>3.0.0-preview-19057-06</MicrosoftNETSdkRazorPackageVersion>
<MicrosoftNETSdkRazorPackageVersion>3.0.0-preview-19064-09</MicrosoftNETSdkRazorPackageVersion>
<MonoCecilPackageVersion>0.10.1</MonoCecilPackageVersion>
<SignalRPackageVersion>3.0.0-alpha1-10605</SignalRPackageVersion>
<TemplateBlazorPackageVersion>0.8.0-preview-19064-0339</TemplateBlazorPackageVersion>
@ -20,7 +20,8 @@
<TemplateRazorDesignPackageVersion>2.1.2</TemplateRazorDesignPackageVersion>
<MicrosoftAspNetCoreBlazorMonoPackageVersion>0.8.0-preview1-20181126.1</MicrosoftAspNetCoreBlazorMonoPackageVersion>
<!-- When updating this, ensure you also update Browser.JS/package.json to reference the corresponding version of @dotnet/jsinterop -->
<JSInteropPackageVersion>0.8.0-preview1-20181126.4</JSInteropPackageVersion>
<MicrosoftJSInteropPackageVersion>3.0.0-preview.19059.5</MicrosoftJSInteropPackageVersion>
<MonoWebAssemblyInteropPackageVersion>0.8.0-preview1-20181126.4</MonoWebAssemblyInteropPackageVersion>
</PropertyGroup>
</Project>

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Description>Support for rendering ASP.NET Core components in browsers.</Description>
<Description>Support for rendering ASP.NET Core components for browsers.</Description>
<IsProductPackage>true</IsProductPackage>
</PropertyGroup>

View File

@ -2,3 +2,5 @@ using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Blazor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Components.Server, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Components.Server.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

View File

@ -12,6 +12,7 @@
<GenerateRazorAssemblyInfo>false</GenerateRazorAssemblyInfo>
<GenerateRazorHostingAssemblyInfo>false</GenerateRazorHostingAssemblyInfo>
<GenerateProvideApplicationPartFactoryAttribute>false</GenerateProvideApplicationPartFactoryAttribute>
<_RazorComponentInclude>**\*.cshtml</_RazorComponentInclude>
</PropertyGroup>
<ItemGroup>
@ -24,8 +25,4 @@
</RazorExtension>
</ItemGroup>
<ItemGroup>
<RazorComponent Include="@(Content->WithMetadataValue('Extension', '.cshtml'))" />
</ItemGroup>
</Project>

View File

@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
{
internal class CircuitHost : IDisposable
{
private static AsyncLocal<CircuitHost> _current = new AsyncLocal<CircuitHost>();
private static readonly AsyncLocal<CircuitHost> _current = new AsyncLocal<CircuitHost>();
/// <summary>
/// Gets the current <see cref="Circuit"/>, if any.
@ -24,23 +24,18 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
public static CircuitHost Current => _current.Value;
/// <summary>
/// Sets the current <see cref="Circuit"/>.
/// Sets the current <see cref="Circuits.Circuit"/>.
/// </summary>
/// <param name="circuitHost">The <see cref="Circuit"/>.</param>
/// <param name="circuitHost">The <see cref="Circuits.Circuit"/>.</param>
/// <remarks>
/// Calling <see cref="SetCurrentCircuitHost(CircuitHost)"/> will store the circuit
/// and other related values such as the <see cref="IJSRuntime"/> and <see cref="Renderer"/>
/// in the local execution context. Application code should not need to call this method,
/// it is primarily used by the Server-Side Blazor infrastructure.
/// it is primarily used by the Server-Side Components infrastructure.
/// </remarks>
public static void SetCurrentCircuitHost(CircuitHost circuitHost)
{
if (circuitHost == null)
{
throw new ArgumentNullException(nameof(circuitHost));
}
_current.Value = circuitHost;
_current.Value = circuitHost ?? throw new ArgumentNullException(nameof(circuitHost));
Microsoft.JSInterop.JSRuntime.SetCurrentJSRuntime(circuitHost.JSRuntime);
RendererRegistry.SetCurrentRendererRegistry(circuitHost.RendererRegistry);
@ -134,6 +129,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
public void Dispose()
{
Scope.Dispose();
Renderer.Dispose();
}
private void AssertInitialized()

View File

@ -120,11 +120,10 @@ namespace Microsoft.AspNetCore.Components.Browser.Rendering
}
}
/// <summary>
/// Disposes the instance.
/// </summary>
public void Dispose()
/// <inheritdoc />
protected override void Dispose(bool disposing)
{
base.Dispose(true);
_rendererRegistry.TryRemove(_id);
}

View File

@ -8,7 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.JSInterop" Version="$(JSInteropPackageVersion)" />
<PackageReference Include="Microsoft.JSInterop" Version="$(MicrosoftJSInteropPackageVersion)" />
</ItemGroup>
</Project>

View File

@ -12,19 +12,17 @@ namespace Microsoft.AspNetCore.Components.Rendering
/// Provides mechanisms for rendering hierarchies of <see cref="IComponent"/> instances,
/// dispatching events to them, and notifying when the user interface is being updated.
/// </summary>
public abstract class Renderer
public abstract class Renderer : IDisposable
{
private readonly ComponentFactory _componentFactory;
private int _nextComponentId = 0; // TODO: change to 'long' when Mono .NET->JS interop supports it
private readonly Dictionary<int, ComponentState> _componentStateById
= new Dictionary<int, ComponentState>();
private readonly Dictionary<int, ComponentState> _componentStateById = new Dictionary<int, ComponentState>();
private readonly RenderBatchBuilder _batchBuilder = new RenderBatchBuilder();
private bool _isBatchInProgress;
private int _lastEventHandlerId = 0;
private readonly Dictionary<int, EventHandlerInvoker> _eventBindings = new Dictionary<int, EventHandlerInvoker>();
private int _nextComponentId = 0; // TODO: change to 'long' when Mono .NET->JS interop supports it
private bool _isBatchInProgress;
private int _lastEventHandlerId = 0;
/// <summary>
/// Constructs an instance of <see cref="Renderer"/>.
/// </summary>
@ -175,7 +173,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
if (frame.AttributeValue is MulticastDelegate @delegate)
{
_eventBindings.Add(id, new EventHandlerInvoker(@delegate));
_eventBindings.Add(id, new EventHandlerInvoker(@delegate));
}
frame = frame.WithAttributeEventHandlerId(id);
@ -295,5 +293,44 @@ namespace Microsoft.AspNetCore.Components.Rendering
RemoveEventHandlerIds(eventHandlerIdsClone, Task.CompletedTask));
}
}
/// <summary>
/// Releases all resources currently used by this <see cref="Renderer"/> instance.
/// </summary>
/// <param name="disposing"><see langword="true"/> if this method is being invoked by <see cref="IDisposable.Dispose"/>, otherwise <see langword="false"/>.</param>
protected virtual void Dispose(bool disposing)
{
List<Exception> exceptions = null;
foreach (var componentState in _componentStateById.Values)
{
if (componentState.Component is IDisposable disposable)
{
try
{
disposable.Dispose();
}
catch (Exception exception)
{
// Capture exceptions thrown by individual components and rethrow as an aggregate.
exceptions = exceptions ?? new List<Exception>();
exceptions.Add(exception);
}
}
}
if (exceptions != null)
{
throw new AggregateException(exceptions);
}
}
/// <summary>
/// Releases all resources currently used by this <see cref="Renderer"/> instance.
/// </summary>
public void Dispose()
{
Dispose(disposing: true);
}
}
}

View File

@ -0,0 +1,61 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Threading;
using Microsoft.AspNetCore.Components.Browser;
using Microsoft.AspNetCore.Components.Browser.Rendering;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.JSInterop;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Components.Server.Circuits
{
public class CircuitHostTest
{
[Fact]
public void Dispose_DisposesResources()
{
// Arrange
var serviceScope = new Mock<IServiceScope>();
var clientProxy = Mock.Of<IClientProxy>();
var renderRegistry = new RendererRegistry();
var jsRuntime = Mock.Of<IJSRuntime>();
var syncContext = new CircuitSynchronizationContext();
var remoteRenderer = new TestRemoteRenderer(
Mock.Of<IServiceProvider>(),
renderRegistry,
jsRuntime,
clientProxy,
syncContext);
var circuitHost = new CircuitHost(serviceScope.Object, clientProxy, renderRegistry, remoteRenderer, configure: _ => { }, jsRuntime: jsRuntime, synchronizationContext: syncContext);
// Act
circuitHost.Dispose();
// Assert
serviceScope.Verify(s => s.Dispose(), Times.Once());
Assert.True(remoteRenderer.Disposed);
}
private class TestRemoteRenderer : RemoteRenderer
{
public TestRemoteRenderer(IServiceProvider serviceProvider, RendererRegistry rendererRegistry, IJSRuntime jsRuntime, IClientProxy client, SynchronizationContext syncContext)
: base(serviceProvider, rendererRegistry, jsRuntime, client, syncContext)
{
}
public bool Disposed { get; set; }
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
Disposed = true;
}
}
}
}

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
@ -7,6 +7,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
<PackageReference Include="Moq" Version="4.10.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
</ItemGroup>

View File

@ -5,7 +5,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
using Microsoft.AspNetCore.Components.RenderTree;
using Microsoft.AspNetCore.Components.Test.Helpers;
@ -1139,6 +1138,78 @@ namespace Microsoft.AspNetCore.Components.Test
Assert.Equal(2, numEventsFired);
}
[Fact]
public void DisposingRenderer_DisposesTopLevelComponents()
{
// Arrange
var renderer = new TestRenderer();
var component = new DisposableComponent();
renderer.AssignRootComponentId(component);
// Act
renderer.Dispose();
// Assert
Assert.True(component.Disposed);
}
[Fact]
public void DisposingRenderer_DisposesNestedComponents()
{
// Arrange
var renderer = new TestRenderer();
var component = new TestComponent(builder =>
{
builder.AddContent(0, "Hello");
builder.OpenComponent<DisposableComponent>(1);
builder.CloseComponent();
});
var componentId = renderer.AssignRootComponentId(component);
component.TriggerRender();
var batch = renderer.Batches.Single();
var componentFrame = batch.ReferenceFrames
.Single(frame => frame.FrameType == RenderTreeFrameType.Component);
var nestedComponent = Assert.IsType<DisposableComponent>(componentFrame.Component);
// Act
renderer.Dispose();
// Assert
Assert.True(component.Disposed);
Assert.True(nestedComponent.Disposed);
}
[Fact]
public void DisposingRenderer_CapturesExceptionsFromAllRegisteredComponents()
{
// Arrange
var renderer = new TestRenderer();
var exception1 = new Exception();
var exception2 = new Exception();
var component = new TestComponent(builder =>
{
builder.AddContent(0, "Hello");
builder.OpenComponent<DisposableComponent>(1);
builder.AddAttribute(1, nameof(DisposableComponent.DisposeAction), (Action)(() => throw exception1));
builder.CloseComponent();
builder.OpenComponent<DisposableComponent>(2);
builder.AddAttribute(1, nameof(DisposableComponent.DisposeAction), (Action)(() => throw exception2));
builder.CloseComponent();
});
var componentId = renderer.AssignRootComponentId(component);
component.TriggerRender();
// Act &A Assert
var aggregate = Assert.Throws<AggregateException>(renderer.Dispose);
// All components must be disposed even if some throw as part of being diposed.
Assert.True(component.Disposed);
Assert.Equal(2, aggregate.InnerExceptions.Count);
Assert.Contains(exception1, aggregate.InnerExceptions);
Assert.Contains(exception2, aggregate.InnerExceptions);
}
private class NoOpRenderer : Renderer
{
public NoOpRenderer() : base(new TestServiceProvider())
@ -1152,7 +1223,7 @@ namespace Microsoft.AspNetCore.Components.Test
=> Task.CompletedTask;
}
private class TestComponent : IComponent
private class TestComponent : IComponent, IDisposable
{
private RenderHandle _renderHandle;
private RenderFragment _renderFragment;
@ -1172,6 +1243,10 @@ namespace Microsoft.AspNetCore.Components.Test
public void TriggerRender()
=> _renderHandle.Render(_renderFragment);
public bool Disposed { get; private set; }
void IDisposable.Dispose() => Disposed = true;
}
private class MessageComponent : AutoRenderComponent
@ -1398,6 +1473,24 @@ namespace Microsoft.AspNetCore.Components.Test
}
}
private class DisposableComponent : AutoRenderComponent, IDisposable
{
public bool Disposed { get; private set; }
[Parameter]
public Action DisposeAction { get; private set; }
public void Dispose()
{
Disposed = true;
DisposeAction?.Invoke();
}
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
}
}
class TestAsyncRenderer : TestRenderer
{
public Task NextUpdateDisplayReturnTask { get; set; }

View File

@ -19,6 +19,8 @@
<Dependency Include="Microsoft.AspNetCore.Authentication" Version="$(MicrosoftAspNetCoreAuthenticationPackageVersion)" />
<Dependency Include="Microsoft.AspNetCore.Authorization.Policy" Version="$(MicrosoftAspNetCoreAuthorizationPolicyPackageVersion)" />
<Dependency Include="Microsoft.AspNetCore.Authorization" Version="$(MicrosoftAspNetCoreAuthorizationPackageVersion)" />
<Dependency Include="Microsoft.AspNetCore.Components" Version="$(MicrosoftAspNetCoreComponentsPackageVersion)" />
<Dependency Include="Microsoft.AspNetCore.Components.Browser" Version="$(MicrosoftAspNetCoreComponentsBrowserPackageVersion)" />
<Dependency Include="Microsoft.AspNetCore.Connections.Abstractions" Version="$(MicrosoftAspNetCoreConnectionsAbstractionsPackageVersion)" />
<Dependency Include="Microsoft.AspNetCore.CookiePolicy" Version="$(MicrosoftAspNetCoreCookiePolicyPackageVersion)" />
<Dependency Include="Microsoft.AspNetCore.Cors" Version="$(MicrosoftAspNetCoreCorsPackageVersion)" />
@ -127,6 +129,7 @@
<Dependency Include="Microsoft.Extensions.Options" Version="$(MicrosoftExtensionsOptionsPackageVersion)" />
<Dependency Include="Microsoft.Extensions.Primitives" Version="$(MicrosoftExtensionsPrimitivesPackageVersion)" />
<Dependency Include="Microsoft.Extensions.WebEncoders" Version="$(MicrosoftExtensionsWebEncodersPackageVersion)" />
<Dependency Include="Microsoft.JSInterop" Version="$(MicrosoftJSInteropPackageVersion)" />
<Dependency Include="Microsoft.Net.Http.Headers" Version="$(MicrosoftNetHttpHeadersPackageVersion)" />
<Dependency Include="Newtonsoft.Json" Version="$(NewtonsoftJsonPackageVersion)" />
<Dependency Include="System.IO.Pipelines" Version="$(SystemIOPipelinesPackageVersion)" />

View File

@ -0,0 +1,128 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.TestHost
{
internal class AsyncStreamWrapper : Stream
{
private Stream _inner;
private Func<bool> _allowSynchronousIO;
internal AsyncStreamWrapper(Stream inner, Func<bool> allowSynchronousIO)
{
_inner = inner;
_allowSynchronousIO = allowSynchronousIO;
}
public override bool CanRead => _inner.CanRead;
public override bool CanSeek => _inner.CanSeek;
public override bool CanWrite => _inner.CanWrite;
public override long Length => _inner.Length;
public override long Position { get => _inner.Position; set => _inner.Position = value; }
public override void Flush()
{
// Not blocking Flush because things like StreamWriter.Dispose() always call it.
_inner.Flush();
}
public override Task FlushAsync(CancellationToken cancellationToken)
{
return _inner.FlushAsync(cancellationToken);
}
public override int Read(byte[] buffer, int offset, int count)
{
if (!_allowSynchronousIO())
{
throw new InvalidOperationException("Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true.");
}
return _inner.Read(buffer, offset, count);
}
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return _inner.ReadAsync(buffer, offset, count, cancellationToken);
}
public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
{
return _inner.ReadAsync(buffer, cancellationToken);
}
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
{
return _inner.BeginRead(buffer, offset, count, callback, state);
}
public override int EndRead(IAsyncResult asyncResult)
{
return _inner.EndRead(asyncResult);
}
public override long Seek(long offset, SeekOrigin origin)
{
return _inner.Seek(offset, origin);
}
public override void SetLength(long value)
{
_inner.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
if (!_allowSynchronousIO())
{
throw new InvalidOperationException("Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true.");
}
_inner.Write(buffer, offset, count);
}
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
{
return _inner.BeginWrite(buffer, offset, count, callback, state);
}
public override void EndWrite(IAsyncResult asyncResult)
{
_inner.EndWrite(asyncResult);
}
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return _inner.WriteAsync(buffer, offset, count, cancellationToken);
}
public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
{
return _inner.WriteAsync(buffer, cancellationToken);
}
public override void Close()
{
_inner.Close();
}
protected override void Dispose(bool disposing)
{
_inner.Dispose();
}
public override ValueTask DisposeAsync()
{
return _inner.DisposeAsync();
}
}
}

View File

@ -43,6 +43,8 @@ namespace Microsoft.AspNetCore.TestHost
_pathBase = pathBase;
}
internal bool AllowSynchronousIO { get; set; }
/// <summary>
/// This adapts HttpRequestMessages to ASP.NET Core requests, dispatches them through the pipeline, and returns the
/// associated HttpResponseMessage.
@ -59,7 +61,7 @@ namespace Microsoft.AspNetCore.TestHost
throw new ArgumentNullException(nameof(request));
}
var contextBuilder = new HttpContextBuilder(_application);
var contextBuilder = new HttpContextBuilder(_application, AllowSynchronousIO);
Stream responseBody = null;
var requestContent = request.Content ?? new StreamContent(Stream.Null);
@ -110,7 +112,7 @@ namespace Microsoft.AspNetCore.TestHost
// This body may have been consumed before, rewind it.
body.Seek(0, SeekOrigin.Begin);
}
req.Body = body;
req.Body = new AsyncStreamWrapper(body, () => contextBuilder.AllowSynchronousIO);
responseBody = context.Response.Body;
});

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
@ -11,7 +11,7 @@ using static Microsoft.AspNetCore.Hosting.Internal.HostingApplication;
namespace Microsoft.AspNetCore.TestHost
{
internal class HttpContextBuilder
internal class HttpContextBuilder : IHttpBodyControlFeature
{
private readonly IHttpApplication<Context> _application;
private readonly HttpContext _httpContext;
@ -23,24 +23,28 @@ namespace Microsoft.AspNetCore.TestHost
private bool _pipelineFinished;
private Context _testContext;
internal HttpContextBuilder(IHttpApplication<Context> application)
internal HttpContextBuilder(IHttpApplication<Context> application, bool allowSynchronousIO)
{
_application = application ?? throw new ArgumentNullException(nameof(application));
AllowSynchronousIO = allowSynchronousIO;
_httpContext = new DefaultHttpContext();
var request = _httpContext.Request;
request.Protocol = "HTTP/1.1";
request.Method = HttpMethods.Get;
_httpContext.Features.Set<IHttpBodyControlFeature>(this);
_httpContext.Features.Set<IHttpResponseFeature>(_responseFeature);
var requestLifetimeFeature = new HttpRequestLifetimeFeature();
requestLifetimeFeature.RequestAborted = _requestAbortedSource.Token;
_httpContext.Features.Set<IHttpRequestLifetimeFeature>(requestLifetimeFeature);
_responseStream = new ResponseStream(ReturnResponseMessageAsync, AbortRequest);
_responseStream = new ResponseStream(ReturnResponseMessageAsync, AbortRequest, () => AllowSynchronousIO);
_responseFeature.Body = _responseStream;
}
public bool AllowSynchronousIO { get; set; }
internal void Configure(Action<HttpContext> configureContext)
{
if (configureContext == null)
@ -136,4 +140,4 @@ namespace Microsoft.AspNetCore.TestHost
_responseTcs.TrySetException(exception);
}
}
}
}

View File

@ -24,13 +24,15 @@ namespace Microsoft.AspNetCore.TestHost
private Func<Task> _onFirstWriteAsync;
private bool _firstWrite;
private Action _abortRequest;
private Func<bool> _allowSynchronousIO;
private Pipe _pipe = new Pipe();
internal ResponseStream(Func<Task> onFirstWriteAsync, Action abortRequest)
internal ResponseStream(Func<Task> onFirstWriteAsync, Action abortRequest, Func<bool> allowSynchronousIO)
{
_onFirstWriteAsync = onFirstWriteAsync ?? throw new ArgumentNullException(nameof(onFirstWriteAsync));
_abortRequest = abortRequest ?? throw new ArgumentNullException(nameof(abortRequest));
_allowSynchronousIO = allowSynchronousIO ?? throw new ArgumentNullException(nameof(allowSynchronousIO));
_firstWrite = true;
_writeLock = new SemaphoreSlim(1, 1);
}
@ -144,6 +146,11 @@ namespace Microsoft.AspNetCore.TestHost
// Write with count 0 will still trigger OnFirstWrite
public override void Write(byte[] buffer, int offset, int count)
{
if (!_allowSynchronousIO())
{
throw new InvalidOperationException("Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true.");
}
// The Pipe Write method requires calling FlushAsync to notify the reader. Call WriteAsync instead.
WriteAsync(buffer, offset, count).GetAwaiter().GetResult();
}

View File

@ -77,6 +77,14 @@ namespace Microsoft.AspNetCore.TestHost
public IFeatureCollection Features { get; }
/// <summary>
/// Gets or sets a value that controls whether synchronous IO is allowed for the <see cref="HttpContext.Request"/> and <see cref="HttpContext.Response"/>
/// </summary>
/// <remarks>
/// Defaults to true.
/// </remarks>
public bool AllowSynchronousIO { get; set; } = true;
private IHttpApplication<Context> Application
{
get => _application ?? throw new InvalidOperationException("The server has not been started or no web application was configured.");
@ -85,7 +93,7 @@ namespace Microsoft.AspNetCore.TestHost
public HttpMessageHandler CreateHandler()
{
var pathBase = BaseAddress == null ? PathString.Empty : PathString.FromUriComponent(BaseAddress);
return new ClientHandler(pathBase, Application);
return new ClientHandler(pathBase, Application) { AllowSynchronousIO = AllowSynchronousIO };
}
public HttpClient CreateClient()
@ -96,7 +104,7 @@ namespace Microsoft.AspNetCore.TestHost
public WebSocketClient CreateWebSocketClient()
{
var pathBase = BaseAddress == null ? PathString.Empty : PathString.FromUriComponent(BaseAddress);
return new WebSocketClient(pathBase, Application);
return new WebSocketClient(pathBase, Application) { AllowSynchronousIO = AllowSynchronousIO };
}
/// <summary>
@ -120,7 +128,7 @@ namespace Microsoft.AspNetCore.TestHost
throw new ArgumentNullException(nameof(configureContext));
}
var builder = new HttpContextBuilder(Application);
var builder = new HttpContextBuilder(Application, AllowSynchronousIO);
builder.Configure(context =>
{
var request = context.Request;
@ -138,6 +146,7 @@ namespace Microsoft.AspNetCore.TestHost
request.PathBase = pathBase;
});
builder.Configure(configureContext);
// TODO: Wrap the request body if any?
return await builder.SendAsync(cancellationToken).ConfigureAwait(false);
}

View File

@ -46,10 +46,12 @@ namespace Microsoft.AspNetCore.TestHost
set;
}
internal bool AllowSynchronousIO { get; set; }
public async Task<WebSocket> ConnectAsync(Uri uri, CancellationToken cancellationToken)
{
WebSocketFeature webSocketFeature = null;
var contextBuilder = new HttpContextBuilder(_application);
var contextBuilder = new HttpContextBuilder(_application, AllowSynchronousIO);
contextBuilder.Configure(context =>
{
var request = context.Request;
@ -131,4 +133,4 @@ namespace Microsoft.AspNetCore.TestHost
}
}
}
}
}

View File

@ -92,13 +92,12 @@ namespace Microsoft.AspNetCore.TestHost
public async Task ResubmitRequestWorks()
{
int requestCount = 1;
var handler = new ClientHandler(PathString.Empty, new DummyApplication(context =>
var handler = new ClientHandler(PathString.Empty, new DummyApplication(async context =>
{
int read = context.Request.Body.Read(new byte[100], 0, 100);
int read = await context.Request.Body.ReadAsync(new byte[100], 0, 100);
Assert.Equal(11, read);
context.Response.Headers["TestHeader"] = "TestValue:" + requestCount++;
return Task.FromResult(0);
}));
HttpMessageInvoker invoker = new HttpMessageInvoker(handler);

View File

@ -109,6 +109,7 @@ namespace Microsoft.AspNetCore.TestHost
{
c.Response.Headers["TestHeader"] = "TestValue";
var bytes = Encoding.UTF8.GetBytes("BodyStarted" + Environment.NewLine);
c.Features.Get<IHttpBodyControlFeature>().AllowSynchronousIO = true;
c.Response.Body.Write(bytes, 0, bytes.Length);
await block.Task;
bytes = Encoding.UTF8.GetBytes("BodyFinished");

View File

@ -87,8 +87,8 @@ namespace Microsoft.AspNetCore.TestHost
public async Task PutAsyncWorks()
{
// Arrange
RequestDelegate appDelegate = ctx =>
ctx.Response.WriteAsync(new StreamReader(ctx.Request.Body).ReadToEnd() + " PUT Response");
RequestDelegate appDelegate = async ctx =>
await ctx.Response.WriteAsync(await new StreamReader(ctx.Request.Body).ReadToEndAsync() + " PUT Response");
var builder = new WebHostBuilder().Configure(app => app.Run(appDelegate));
var server = new TestServer(builder);
var client = server.CreateClient();
@ -106,7 +106,7 @@ namespace Microsoft.AspNetCore.TestHost
{
// Arrange
RequestDelegate appDelegate = async ctx =>
await ctx.Response.WriteAsync(new StreamReader(ctx.Request.Body).ReadToEnd() + " POST Response");
await ctx.Response.WriteAsync(await new StreamReader(ctx.Request.Body).ReadToEndAsync() + " POST Response");
var builder = new WebHostBuilder().Configure(app => app.Run(appDelegate));
var server = new TestServer(builder);
var client = server.CreateClient();
@ -132,16 +132,15 @@ namespace Microsoft.AspNetCore.TestHost
}
var builder = new WebHostBuilder();
RequestDelegate app = (ctx) =>
RequestDelegate app = async ctx =>
{
var disposable = new TestDisposable();
ctx.Response.RegisterForDispose(disposable);
ctx.Response.Body.Write(data, 0, 1024);
await ctx.Response.Body.WriteAsync(data, 0, 1024);
Assert.False(disposable.IsDisposed);
ctx.Response.Body.Write(data, 1024, 1024);
return Task.FromResult(0);
await ctx.Response.Body.WriteAsync(data, 1024, 1024);
};
builder.Configure(appBuilder => appBuilder.Run(app));

View File

@ -22,7 +22,6 @@ Microsoft.AspNetCore.Http.HttpResponse</Description>
<Reference Include="Microsoft.AspNetCore.Http.Features" />
<Reference Include="Microsoft.Extensions.ActivatorUtilities.Sources" PrivateAssets="All" />
<Reference Include="System.Text.Encodings.Web" />
<Reference Include="System.IO.Pipelines" />
</ItemGroup>
</Project>

View File

@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Http.Features
public interface IRequestBodyPipeFeature
{
/// <summary>
/// A <see cref="PipeWriter"/> representing the request body, if any.
/// A <see cref="PipeReader"/> representing the request body, if any.
/// </summary>
PipeReader RequestBodyPipe { get; set; }
}

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.0;net461</TargetFrameworks>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
<ItemGroup>

View File

@ -7,7 +7,7 @@ using System.Runtime.CompilerServices;
namespace System.IO.Pipelines
{
public sealed class BufferSegment : ReadOnlySequenceSegment<byte>
internal sealed class BufferSegment : ReadOnlySequenceSegment<byte>
{
private IMemoryOwner<byte> _memoryOwner;
private BufferSegment _next;

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>ASP.NET Core default HTTP feature implementations.</Description>
@ -19,7 +19,6 @@
<Reference Include="Microsoft.Extensions.ObjectPool" />
<Reference Include="Microsoft.Extensions.Options" />
<Reference Include="Microsoft.Net.Http.Headers" />
<Reference Include="System.IO.Pipelines" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Http.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

View File

@ -0,0 +1,240 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Buffers;
using System.Threading;
using System.Threading.Tasks;
namespace System.IO.Pipelines
{
/// <summary>
/// Represents a read-only Stream backed by a PipeReader
/// </summary>
public class ReadOnlyPipeStream : Stream
{
private readonly PipeReader _pipeReader;
private bool _allowSynchronousIO = true;
/// <summary>
/// Creates a new ReadOnlyPipeStream
/// </summary>
/// <param name="pipeReader">The PipeReader to read from.</param>
public ReadOnlyPipeStream(PipeReader pipeReader) :
this(pipeReader, allowSynchronousIO: true)
{
}
/// <summary>
/// Creates a new ReadOnlyPipeStream
/// </summary>
/// <param name="pipeReader">The PipeReader to read from.</param>
/// <param name="allowSynchronousIO">Whether synchronous IO is allowed.</param>
public ReadOnlyPipeStream(PipeReader pipeReader, bool allowSynchronousIO)
{
_allowSynchronousIO = allowSynchronousIO;
_pipeReader = pipeReader;
}
/// <inheritdoc />
public override bool CanSeek => false;
/// <inheritdoc />
public override bool CanRead => true;
/// <inheritdoc />
public override bool CanWrite => false;
/// <inheritdoc />
public override long Length => throw new NotSupportedException();
/// <inheritdoc />
public override long Position
{
get => throw new NotSupportedException();
set => throw new NotSupportedException();
}
/// <inheritdoc />
public override int WriteTimeout
{
get => throw new NotSupportedException();
set => throw new NotSupportedException();
}
/// <inheritdoc />
public override void Write(byte[] buffer, int offset, int count)
=> throw new NotSupportedException();
/// <inheritdoc />
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
=> throw new NotSupportedException();
/// <inheritdoc />
public override void Flush()
{
throw new NotSupportedException();
}
/// <inheritdoc />
public override Task FlushAsync(CancellationToken cancellationToken)
{
throw new NotSupportedException();
}
/// <inheritdoc />
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
/// <inheritdoc />
public override void SetLength(long value)
{
throw new NotSupportedException();
}
/// <inheritdoc />
public override int Read(byte[] buffer, int offset, int count)
{
if (!_allowSynchronousIO)
{
ThrowHelper.ThrowInvalidOperationException_SynchronousReadsDisallowed();
}
return ReadAsync(buffer, offset, count).GetAwaiter().GetResult();
}
/// <inheritdoc />
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
{
var task = ReadAsync(buffer, offset, count, default, state);
if (callback != null)
{
task.ContinueWith(t => callback.Invoke(t));
}
return task;
}
/// <inheritdoc />
public override int EndRead(IAsyncResult asyncResult)
{
return ((Task<int>)asyncResult).GetAwaiter().GetResult();
}
private Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken, object state)
{
var tcs = new TaskCompletionSource<int>(state);
var task = ReadAsync(buffer, offset, count, cancellationToken);
task.ContinueWith((task2, state2) =>
{
var tcs2 = (TaskCompletionSource<int>)state2;
if (task2.IsCanceled)
{
tcs2.SetCanceled();
}
else if (task2.IsFaulted)
{
tcs2.SetException(task2.Exception);
}
else
{
tcs2.SetResult(task2.Result);
}
}, tcs, cancellationToken);
return tcs.Task;
}
/// <inheritdoc />
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return ReadAsyncInternal(new Memory<byte>(buffer, offset, count), cancellationToken).AsTask();
}
/// <inheritdoc />
public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default)
{
return ReadAsyncInternal(destination, cancellationToken);
}
private async ValueTask<int> ReadAsyncInternal(Memory<byte> buffer, CancellationToken cancellationToken)
{
while (true)
{
var result = await _pipeReader.ReadAsync(cancellationToken);
var readableBuffer = result.Buffer;
var readableBufferLength = readableBuffer.Length;
var consumed = readableBuffer.End;
var actual = 0;
try
{
if (readableBufferLength != 0)
{
actual = (int)Math.Min(readableBufferLength, buffer.Length);
var slice = actual == readableBufferLength ? readableBuffer : readableBuffer.Slice(0, actual);
consumed = slice.End;
slice.CopyTo(buffer.Span);
return actual;
}
if (result.IsCompleted)
{
return 0;
}
}
finally
{
_pipeReader.AdvanceTo(consumed);
}
}
}
/// <inheritdoc />
public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
{
if (destination == null)
{
throw new ArgumentNullException(nameof(destination));
}
if (bufferSize <= 0)
{
throw new ArgumentOutOfRangeException(nameof(bufferSize));
}
return CopyToAsyncInternal(destination, cancellationToken);
}
private async Task CopyToAsyncInternal(Stream destination, CancellationToken cancellationToken)
{
while (true)
{
var result = await _pipeReader.ReadAsync(cancellationToken);
var readableBuffer = result.Buffer;
var readableBufferLength = readableBuffer.Length;
try
{
if (readableBufferLength != 0)
{
foreach (var memory in readableBuffer)
{
await destination.WriteAsync(memory, cancellationToken);
}
}
if (result.IsCompleted)
{
return;
}
}
finally
{
_pipeReader.AdvanceTo(readableBuffer.End);
}
}
}
}
}

View File

@ -25,7 +25,8 @@ namespace System.IO.Pipelines
private readonly MemoryPool<byte> _pool;
private CancellationTokenSource _internalTokenSource;
private bool _isCompleted;
private bool _isReaderCompleted;
private bool _isWriterCompleted;
private ExceptionDispatchInfo _exceptionInfo;
private BufferSegment _readHead;
@ -182,12 +183,12 @@ namespace System.IO.Pipelines
/// <inheritdoc />
public override void Complete(Exception exception = null)
{
if (_isCompleted)
if (_isReaderCompleted)
{
return;
}
_isCompleted = true;
_isReaderCompleted = true;
if (exception != null)
{
_exceptionInfo = ExceptionDispatchInfo.Capture(exception);
@ -248,6 +249,11 @@ namespace System.IO.Pipelines
_readTail.End += length;
_bufferedBytes += length;
if (length == 0)
{
_isWriterCompleted = true;
}
}
catch (OperationCanceledException)
{
@ -275,7 +281,7 @@ namespace System.IO.Pipelines
private void ThrowIfCompleted()
{
if (_isCompleted)
if (_isReaderCompleted)
{
ThrowHelper.ThrowInvalidOperationException_NoReadingAllowed();
}
@ -357,7 +363,7 @@ namespace System.IO.Pipelines
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool IsCompletedOrThrow()
{
if (!_isCompleted)
if (!_isWriterCompleted)
{
return false;
}

View File

@ -65,7 +65,7 @@ namespace System.IO.Pipelines
}
/// <summary>
/// Gets the inner stream that is being read from.
/// Gets the inner stream that is being written to.
/// </summary>
public Stream InnerStream => _writingStream;

View File

@ -19,5 +19,17 @@ namespace System.IO.Pipelines
public static void ThrowInvalidOperationException_NoDataRead() => throw CreateInvalidOperationException_NoDataRead();
[MethodImpl(MethodImplOptions.NoInlining)]
public static Exception CreateInvalidOperationException_NoDataRead() => new InvalidOperationException("No data has been read into the StreamPipeReader.");
public static void ThrowInvalidOperationException_SynchronousReadsDisallowed() => throw CreateInvalidOperationException_SynchronousReadsDisallowed();
[MethodImpl(MethodImplOptions.NoInlining)]
public static Exception CreateInvalidOperationException_SynchronousReadsDisallowed() => new InvalidOperationException("Synchronous operations are disallowed. Call ReadAsync or set allowSynchronousIO to true instead.");
public static void ThrowInvalidOperationException_SynchronousWritesDisallowed() => throw CreateInvalidOperationException_SynchronousWritesDisallowed();
[MethodImpl(MethodImplOptions.NoInlining)]
public static Exception CreateInvalidOperationException_SynchronousWritesDisallowed() => new InvalidOperationException("Synchronous operations are disallowed. Call WriteAsync or set allowSynchronousIO to true instead.");
public static void ThrowInvalidOperationException_SynchronousFlushesDisallowed() => throw CreateInvalidOperationException_SynchronousFlushesDisallowed();
[MethodImpl(MethodImplOptions.NoInlining)]
public static Exception CreateInvalidOperationException_SynchronousFlushesDisallowed() => new InvalidOperationException("Synchronous operations are disallowed. Call FlushAsync or set allowSynchronousIO to true instead.");
}
}

View File

@ -0,0 +1,162 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading;
using System.Threading.Tasks;
namespace System.IO.Pipelines
{
/// <summary>
/// Represents a WriteOnlyStream backed by a PipeWriter
/// </summary>
public class WriteOnlyPipeStream : Stream
{
private PipeWriter _pipeWriter;
private bool _allowSynchronousIO = true;
/// <summary>
/// Creates a new WriteOnlyStream
/// </summary>
/// <param name="pipeWriter">The PipeWriter to write to.</param>
public WriteOnlyPipeStream(PipeWriter pipeWriter) :
this(pipeWriter, allowSynchronousIO: true)
{
}
/// <summary>
/// Creates a new WriteOnlyStream
/// </summary>
/// <param name="pipeWriter">The PipeWriter to write to.</param>
/// <param name="allowSynchronousIO">Whether synchronous IO is allowed.</param>
public WriteOnlyPipeStream(PipeWriter pipeWriter, bool allowSynchronousIO)
{
_pipeWriter = pipeWriter;
_allowSynchronousIO = allowSynchronousIO;
}
/// <inheritdoc />
public override bool CanSeek => false;
/// <inheritdoc />
public override bool CanRead => false;
/// <inheritdoc />
public override bool CanWrite => true;
/// <inheritdoc />
public override long Length => throw new NotSupportedException();
/// <inheritdoc />
public override long Position
{
get => throw new NotSupportedException();
set => throw new NotSupportedException();
}
/// <inheritdoc />
public override int ReadTimeout
{
get => throw new NotSupportedException();
set => throw new NotSupportedException();
}
/// <inheritdoc />
public override int Read(byte[] buffer, int offset, int count)
=> throw new NotSupportedException();
/// <inheritdoc />
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
=> throw new NotSupportedException();
/// <inheritdoc />
public override void Flush()
{
if (!_allowSynchronousIO)
{
ThrowHelper.ThrowInvalidOperationException_SynchronousFlushesDisallowed();
}
FlushAsync(default).GetAwaiter().GetResult();
}
/// <inheritdoc />
public override async Task FlushAsync(CancellationToken cancellationToken)
{
await _pipeWriter.FlushAsync(cancellationToken);
}
/// <inheritdoc />
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
/// <inheritdoc />
public override void SetLength(long value)
{
throw new NotSupportedException();
}
/// <inheritdoc />
public override void Write(byte[] buffer, int offset, int count)
{
if (!_allowSynchronousIO)
{
ThrowHelper.ThrowInvalidOperationException_SynchronousWritesDisallowed();
}
WriteAsync(buffer, offset, count, default).GetAwaiter().GetResult();
}
/// <inheritdoc />
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
{
var task = WriteAsync(buffer, offset, count, default, state);
if (callback != null)
{
task.ContinueWith(t => callback.Invoke(t));
}
return task;
}
/// <inheritdoc />
public override void EndWrite(IAsyncResult asyncResult)
{
((Task<object>)asyncResult).GetAwaiter().GetResult();
}
private Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken, object state)
{
var tcs = new TaskCompletionSource<object>(state);
var task = WriteAsync(buffer, offset, count, cancellationToken);
task.ContinueWith((task2, state2) =>
{
var tcs2 = (TaskCompletionSource<object>)state2;
if (task2.IsCanceled)
{
tcs2.SetCanceled();
}
else if (task2.IsFaulted)
{
tcs2.SetException(task2.Exception);
}
else
{
tcs2.SetResult(null);
}
}, tcs, cancellationToken);
return tcs.Task;
}
/// <inheritdoc />
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return WriteAsync(new ReadOnlyMemory<byte>(buffer, offset, count), cancellationToken).AsTask();
}
/// <inheritdoc />
public override async ValueTask WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken = default)
{
await _pipeWriter.WriteAsync(source, cancellationToken);
}
}
}

View File

@ -10,7 +10,7 @@ using Xunit;
namespace System.IO.Pipelines.Tests
{
public class FlushResultCancellationTests : PipeTest
public class FlushResultCancellationTests : StreamPipeTest
{
[Fact]
public async Task FlushAsyncWithNewCancellationTokenNotAffectedByPrevious()

View File

@ -0,0 +1,85 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Buffers;
using System.Text;
using System.Threading.Tasks;
namespace System.IO.Pipelines.Tests
{
public class PipeStreamTest : IDisposable
{
public Stream ReadingStream { get; set; }
public Stream WritingStream { get; set; }
public Pipe Pipe { get; set; }
public PipeReader Reader => Pipe.Reader;
public PipeWriter Writer => Pipe.Writer;
public PipeStreamTest()
{
Pipe = new Pipe();
ReadingStream = new ReadOnlyPipeStream(Reader);
WritingStream = new WriteOnlyPipeStream(Writer);
}
public void Dispose()
{
Writer.Complete();
Reader.Complete();
}
public async Task WriteStringToStreamAsync(string input)
{
await WritingStream.WriteAsync(Encoding.ASCII.GetBytes(input));
}
public async Task WriteStringToPipeAsync(string input)
{
await Writer.WriteAsync(Encoding.ASCII.GetBytes(input));
}
public async Task WriteByteArrayToPipeAsync(byte[] input)
{
await Writer.WriteAsync(input);
}
public async Task<string> ReadFromPipeAsStringAsync()
{
var readResult = await Reader.ReadAsync();
var result = Encoding.ASCII.GetString(readResult.Buffer.ToArray());
Reader.AdvanceTo(readResult.Buffer.End);
return result;
}
public async Task<string> ReadFromStreamAsStringAsync()
{
var memory = new Memory<byte>(new byte[4096]);
var readLength = await ReadingStream.ReadAsync(memory);
var result = Encoding.ASCII.GetString(memory.ToArray(), 0, readLength);
return result;
}
public async Task<byte[]> ReadFromPipeAsByteArrayAsync()
{
var readResult = await Reader.ReadAsync();
var result = readResult.Buffer.ToArray();
Reader.AdvanceTo(readResult.Buffer.End);
return result;
}
public Task<byte[]> ReadFromStreamAsByteArrayAsync(int size)
{
return ReadFromStreamAsByteArrayAsync(size, ReadingStream);
}
public async Task<byte[]> ReadFromStreamAsByteArrayAsync(int size, Stream stream)
{
var memory = new Memory<byte>(new byte[size]);
var readLength = await stream.ReadAsync(memory);
return memory.Slice(0, readLength).ToArray();
}
}
}

View File

@ -12,7 +12,7 @@ using Xunit;
namespace System.IO.Pipelines.Tests
{
public class PipeWriterTests : PipeTest
public class PipeWriterTests : StreamPipeTest
{
[Theory]

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
@ -12,7 +12,7 @@ using Xunit;
namespace System.IO.Pipelines.Tests
{
public class ReadAsyncCancellationTests : PipeTest
public class ReadAsyncCancellationTests : StreamPipeTest
{
[Fact]
public async Task AdvanceShouldResetStateIfReadCanceled()

View File

@ -0,0 +1,164 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Buffers;
using System.Threading;
using System.Threading.Tasks;
using Moq;
using Xunit;
namespace System.IO.Pipelines.Tests
{
public class ReadOnlyPipeStreamTests : PipeStreamTest
{
[Fact]
public void CanSeekFalse()
{
Assert.False(ReadingStream.CanSeek);
}
[Fact]
public void CanReadTrue()
{
Assert.True(ReadingStream.CanRead);
}
[Fact]
public void CanWriteFalse()
{
Assert.False(ReadingStream.CanWrite);
}
[Fact]
public void LengthThrows()
{
Assert.Throws<NotSupportedException>(() => ReadingStream.Length);
}
[Fact]
public void PositionThrows()
{
Assert.Throws<NotSupportedException>(() => ReadingStream.Position);
Assert.Throws<NotSupportedException>(() => ReadingStream.Position = 1);
}
[Fact]
public void SeekThrows()
{
Assert.Throws<NotSupportedException>(() => ReadingStream.Seek(0, SeekOrigin.Begin));
}
[Fact]
public void SetLengthThrows()
{
Assert.Throws<NotSupportedException>(() => ReadingStream.SetLength(1));
}
[Fact]
public void WriteThrows()
{
Assert.Throws<NotSupportedException>(() => ReadingStream.Write(new byte[1], 0, 1));
}
[Fact]
public async Task WriteAsyncThrows()
{
await Assert.ThrowsAsync<NotSupportedException>(async () => await ReadingStream.WriteAsync(new byte[1], 0, 1));
}
[Fact]
public void ReadTimeoutThrows()
{
Assert.Throws<NotSupportedException>(() => ReadingStream.WriteTimeout = 1);
Assert.Throws<NotSupportedException>(() => ReadingStream.WriteTimeout);
}
[Fact]
public async Task ReadAsyncWorks()
{
var expected = "Hello World!";
await WriteStringToPipeAsync(expected);
Assert.Equal(expected, await ReadFromStreamAsStringAsync());
}
[Fact]
public async Task BasicLargeRead()
{
var expected = new byte[8000];
await WriteByteArrayToPipeAsync(expected);
Assert.Equal(expected, await ReadFromStreamAsByteArrayAsync(8000));
}
[Fact]
public async Task ReadAsyncIsCalledFromCallingRead()
{
var pipeReader = await SetupMockPipeReader();
var stream = new ReadOnlyPipeStream(pipeReader.Object);
stream.Read(new byte[1]);
pipeReader.Verify(m => m.ReadAsync(It.IsAny<CancellationToken>()));
}
[Fact]
public async Task ReadAsyncIsCalledFromCallingReadAsync()
{
var pipeReader = await SetupMockPipeReader();
var stream = new ReadOnlyPipeStream(pipeReader.Object);
await stream.ReadAsync(new byte[1]);
pipeReader.Verify(m => m.ReadAsync(It.IsAny<CancellationToken>()));
}
[Fact]
public async Task ReadAsyncCancellationTokenIsPassedIntoReadAsync()
{
var pipeReader = await SetupMockPipeReader();
var stream = new ReadOnlyPipeStream(pipeReader.Object);
var token = new CancellationToken();
await stream.ReadAsync(new byte[1], token);
pipeReader.Verify(m => m.ReadAsync(token));
}
[Fact]
public async Task CopyToAsyncWorks()
{
const int expectedSize = 8000;
var expected = new byte[expectedSize];
await WriteByteArrayToPipeAsync(expected);
Writer.Complete();
var destStream = new MemoryStream();
await ReadingStream.CopyToAsync(destStream);
Assert.Equal(expectedSize, destStream.Length);
}
[Fact]
public void BlockSyncIOThrows()
{
var readOnlyPipeStream = new ReadOnlyPipeStream(Reader, allowSynchronousIO: false);
Assert.Throws<InvalidOperationException>(() => readOnlyPipeStream.Read(new byte[0], 0, 0));
}
private async Task<Mock<PipeReader>> SetupMockPipeReader()
{
await WriteByteArrayToPipeAsync(new byte[1]);
var pipeReader = new Mock<PipeReader>();
pipeReader
.Setup(m => m.ReadAsync(It.IsAny<CancellationToken>()))
.Returns(new ValueTask<ReadResult>(new ReadResult(new ReadOnlySequence<byte>(new byte[1]), false, false)));
return pipeReader;
}
}
}

View File

@ -0,0 +1,147 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Buffers;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
namespace System.IO.Pipelines.Tests
{
public class ReadingAdaptersInteropTests
{
[Fact]
public async Task CheckBasicReadPipeApi()
{
var pipe = new Pipe();
var readStream = new ReadOnlyPipeStream(pipe.Reader);
var pipeReader = new StreamPipeReader(readStream);
await pipe.Writer.WriteAsync(new byte[10]);
var res = await pipeReader.ReadAsync();
Assert.Equal(new byte[10], res.Buffer.ToArray());
}
[Fact]
public async Task CheckNestedPipeApi()
{
var pipe = new Pipe();
var reader = pipe.Reader;
for (var i = 0; i < 3; i++)
{
var readStream = new ReadOnlyPipeStream(reader);
reader = new StreamPipeReader(readStream);
}
await pipe.Writer.WriteAsync(new byte[10]);
var res = await reader.ReadAsync();
Assert.Equal(new byte[10], res.Buffer.ToArray());
}
[Fact]
public async Task CheckBasicReadStreamApi()
{
var stream = new MemoryStream();
await stream.WriteAsync(new byte[10]);
stream.Position = 0;
var pipeReader = new StreamPipeReader(stream);
var readOnlyStream = new ReadOnlyPipeStream(pipeReader);
var resSize = await readOnlyStream.ReadAsync(new byte[10]);
Assert.Equal(10, resSize);
}
[Fact]
public async Task CheckNestedStreamApi()
{
var stream = new MemoryStream();
await stream.WriteAsync(new byte[10]);
stream.Position = 0;
Stream readOnlyStream = stream;
for (var i = 0; i < 3; i++)
{
var pipeReader = new StreamPipeReader(readOnlyStream);
readOnlyStream = new ReadOnlyPipeStream(pipeReader);
}
var resSize = await readOnlyStream.ReadAsync(new byte[10]);
Assert.Equal(10, resSize);
}
[Fact]
public async Task ReadsCanBeCanceledViaProvidedCancellationToken()
{
var readOnlyStream = new ReadOnlyPipeStream(new HangingPipeReader());
var pipeReader = new StreamPipeReader(readOnlyStream);
var cts = new CancellationTokenSource(1);
await Task.Delay(1);
await Assert.ThrowsAsync<TaskCanceledException>(async () => await pipeReader.ReadAsync(cts.Token));
}
[Fact]
public async Task ReadCanBeCancelledViaCancelPendingReadWhenReadIsAsync()
{
var readOnlyStream = new ReadOnlyPipeStream(new HangingPipeReader());
var pipeReader = new StreamPipeReader(readOnlyStream);
var result = new ReadResult();
var tcs = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var task = Task.Run(async () =>
{
var readingTask = pipeReader.ReadAsync();
tcs.SetResult(0);
result = await readingTask;
});
await tcs.Task;
pipeReader.CancelPendingRead();
await task;
Assert.True(result.IsCanceled);
}
private class HangingPipeReader : PipeReader
{
public override void AdvanceTo(SequencePosition consumed)
{
throw new NotImplementedException();
}
public override void AdvanceTo(SequencePosition consumed, SequencePosition examined)
{
throw new NotImplementedException();
}
public override void CancelPendingRead()
{
throw new NotImplementedException();
}
public override void Complete(Exception exception = null)
{
throw new NotImplementedException();
}
public override void OnWriterCompleted(Action<Exception, object> callback, object state)
{
throw new NotImplementedException();
}
public override async ValueTask<ReadResult> ReadAsync(CancellationToken cancellationToken = default)
{
await Task.Delay(30000, cancellationToken);
return new ReadResult();
}
public override bool TryRead(out ReadResult result)
{
result = new ReadResult();
return false;
}
}
}
}

View File

@ -11,7 +11,7 @@ using Xunit;
namespace System.IO.Pipelines.Tests
{
public partial class StreamPipeReaderTests : PipeTest
public partial class StreamPipeReaderTests : StreamPipeTest
{
[Fact]
public async Task CanRead()
@ -198,6 +198,8 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task ReadAsyncReturnsCanceledInterleaved()
{
Write(new byte[10000]);
// Cancel and Read interleaved to confirm cancellations are independent
for (var i = 0; i < 3; i++)
{
@ -501,22 +503,6 @@ namespace System.IO.Pipelines.Tests
Assert.False(readResult.Buffer.IsSingleSegment);
}
[Fact]
public async Task SetMinimumReadThresholdToMiminumSegmentSizeOnlyGetNewBlockWhenDataIsWritten()
{
CreateReader(minimumReadThreshold: 16);
WriteByteArray(0);
var readResult = await Reader.ReadAsync();
Reader.AdvanceTo(readResult.Buffer.Start, readResult.Buffer.End);
WriteByteArray(16);
readResult = await Reader.ReadAsync();
Assert.Equal(16, readResult.Buffer.Length);
Assert.True(readResult.Buffer.IsSingleSegment);
}
[Fact]
public void SetMinimumReadThresholdOfZeroThrows()
{
@ -595,6 +581,24 @@ namespace System.IO.Pipelines.Tests
Assert.Equal("c", ReadFromStreamAsString(buffer));
}
[Fact]
public async Task ReadAsyncWithNoDataCompletesReader()
{
var readResult = await Reader.ReadAsync();
Assert.True(readResult.IsCompleted);
}
[Fact]
public async Task ReadAsyncWithEmptyDataCompletesStream()
{
WriteByteArray(0);
var readResult = await Reader.ReadAsync();
Assert.True(readResult.IsCompleted);
}
private async Task<string> ReadFromPipeAsString()
{
var readResult = await Reader.ReadAsync();

View File

@ -1,14 +1,11 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.IO.Pipelines;
using System.Text;
namespace System.IO.Pipelines.Tests
{
public abstract class PipeTest : IDisposable
public abstract class StreamPipeTest : IDisposable
{
protected const int MaximumSizeHigh = 65;
@ -20,7 +17,7 @@ namespace System.IO.Pipelines.Tests
public PipeReader Reader { get; set; }
protected PipeTest()
protected StreamPipeTest()
{
MemoryStream = new MemoryStream();
Writer = new StreamPipeWriter(MemoryStream, MinimumSegmentSize, new TestMemoryPool());

View File

@ -12,7 +12,7 @@ using Xunit;
namespace System.IO.Pipelines.Tests
{
public class StreamPipeWriterTests : PipeTest
public class StreamPipeWriterTests : StreamPipeTest
{
[Fact]
public async Task CanWriteAsyncMultipleTimesIntoSameBlock()

View File

@ -0,0 +1,199 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading;
using System.Threading.Tasks;
using Moq;
using Xunit;
namespace System.IO.Pipelines.Tests
{
public class WriteOnlyPipeStreamTests : PipeStreamTest
{
[Fact]
public void CanSeekFalse()
{
Assert.False(WritingStream.CanSeek);
}
[Fact]
public void CanReadFalse()
{
Assert.False(WritingStream.CanRead);
}
[Fact]
public void CanWriteTrue()
{
Assert.True(WritingStream.CanWrite);
}
[Fact]
public void LengthThrows()
{
Assert.Throws<NotSupportedException>(() => WritingStream.Length);
}
[Fact]
public void PositionThrows()
{
Assert.Throws<NotSupportedException>(() => WritingStream.Position);
Assert.Throws<NotSupportedException>(() => WritingStream.Position = 1);
}
[Fact]
public void SeekThrows()
{
Assert.Throws<NotSupportedException>(() => WritingStream.Seek(0, SeekOrigin.Begin));
}
[Fact]
public void SetLengthThrows()
{
Assert.Throws<NotSupportedException>(() => WritingStream.SetLength(1));
}
[Fact]
public void ReadThrows()
{
Assert.Throws<NotSupportedException>(() => WritingStream.Read(new byte[1], 0, 1));
}
[Fact]
public async Task ReadAsyncThrows()
{
await Assert.ThrowsAsync<NotSupportedException>(async () => await WritingStream.ReadAsync(new byte[1], 0, 1));
}
[Fact]
public void ReadTimeoutThrows()
{
Assert.Throws<NotSupportedException>(() => WritingStream.ReadTimeout = 1);
Assert.Throws<NotSupportedException>(() => WritingStream.ReadTimeout);
}
[Fact]
public async Task WriteAsyncWithReadOnlyMemoryWorks()
{
var expected = "Hello World!";
await WriteStringToStreamAsync(expected);
Assert.Equal(expected, await ReadFromPipeAsStringAsync());
}
[Fact]
public async Task WriteAsyncWithArrayWorks()
{
var expected = new byte[1];
await WritingStream.WriteAsync(expected, 0, expected.Length);
Assert.Equal(expected, await ReadFromPipeAsByteArrayAsync());
}
[Fact]
public async Task BasicLargeWrite()
{
var expected = new byte[8000];
await WritingStream.WriteAsync(expected);
Assert.Equal(expected, await ReadFromPipeAsByteArrayAsync());
}
[Fact]
public void FlushAsyncIsCalledFromCallingFlush()
{
var pipeWriter = new Mock<PipeWriter>();
var stream = new WriteOnlyPipeStream(pipeWriter.Object);
stream.Flush();
pipeWriter.Verify(m => m.FlushAsync(default));
}
[Fact]
public async Task FlushAsyncIsCalledFromCallingFlushAsync()
{
var pipeWriter = new Mock<PipeWriter>();
var stream = new WriteOnlyPipeStream(pipeWriter.Object);
await stream.FlushAsync();
pipeWriter.Verify(m => m.FlushAsync(default));
}
[Fact]
public async Task FlushAsyncCancellationTokenIsPassedIntoFlushAsync()
{
var pipeWriter = new Mock<PipeWriter>();
var stream = new WriteOnlyPipeStream(pipeWriter.Object);
var token = new CancellationToken();
await stream.FlushAsync(token);
pipeWriter.Verify(m => m.FlushAsync(token));
}
[Fact]
public void WriteAsyncIsCalledFromCallingWrite()
{
var pipeWriter = new Mock<PipeWriter>();
var stream = new WriteOnlyPipeStream(pipeWriter.Object);
stream.Write(new byte[1]);
pipeWriter.Verify(m => m.WriteAsync(It.IsAny<ReadOnlyMemory<byte>>(), It.IsAny<CancellationToken>()));
}
[Fact]
public async Task WriteAsyncIsCalledFromCallingWriteAsync()
{
var pipeWriter = new Mock<PipeWriter>();
var stream = new WriteOnlyPipeStream(pipeWriter.Object);
await stream.WriteAsync(new byte[1]);
pipeWriter.Verify(m => m.WriteAsync(It.IsAny<ReadOnlyMemory<byte>>(), It.IsAny<CancellationToken>()));
}
[Fact]
public async Task WriteAsyncCancellationTokenIsPassedIntoWriteAsync()
{
var pipeWriter = new Mock<PipeWriter>();
var stream = new WriteOnlyPipeStream(pipeWriter.Object);
var token = new CancellationToken();
await stream.WriteAsync(new byte[1], token);
pipeWriter.Verify(m => m.WriteAsync(It.IsAny<ReadOnlyMemory<byte>>(), token));
}
[Fact]
public void WriteAsyncIsCalledFromBeginWrite()
{
var pipeWriter = new Mock<PipeWriter>();
var stream = new WriteOnlyPipeStream(pipeWriter.Object);
stream.BeginWrite(new byte[1], 0, 1, null, this);
pipeWriter.Verify(m => m.WriteAsync(It.IsAny<ReadOnlyMemory<byte>>(), It.IsAny<CancellationToken>()));
}
[Fact]
public async Task BeginAndEndWriteWork()
{
var expected = new byte[1];
var asyncResult = WritingStream.BeginWrite(expected, 0, 1, null, this);
WritingStream.EndWrite(asyncResult);
Assert.Equal(expected, await ReadFromPipeAsByteArrayAsync());
}
[Fact]
public void BlockSyncIOThrows()
{
var writeOnlyPipeStream = new WriteOnlyPipeStream(Writer, allowSynchronousIO: false);
Assert.Throws<InvalidOperationException>(() => writeOnlyPipeStream.Write(new byte[0], 0, 0));
Assert.Throws<InvalidOperationException>(() => writeOnlyPipeStream.Flush());
}
}
}

View File

@ -0,0 +1,155 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Buffers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
namespace System.IO.Pipelines.Tests
{
public class WritingAdaptersInteropTests : PipeStreamTest
{
[Fact]
public async Task CheckBasicWritePipeApi()
{
var pipe = new Pipe();
var writeOnlyStream = new WriteOnlyPipeStream(pipe.Writer);
var pipeWriter = new StreamPipeWriter(writeOnlyStream);
await pipeWriter.WriteAsync(new byte[10]);
var res = await pipe.Reader.ReadAsync();
Assert.Equal(new byte[10], res.Buffer.ToArray());
}
[Fact]
public async Task CheckNestedPipeApi()
{
var pipe = new Pipe();
var writer = pipe.Writer;
for (var i = 0; i < 3; i++)
{
var writeOnlyStream = new WriteOnlyPipeStream(writer);
writer = new StreamPipeWriter(writeOnlyStream);
}
await writer.WriteAsync(new byte[10]);
var res = await pipe.Reader.ReadAsync();
Assert.Equal(new byte[10], res.Buffer.ToArray());
}
[Fact]
public async Task CheckBasicWriteStreamApi()
{
var stream = new MemoryStream();
var pipeWriter = new StreamPipeWriter(stream);
var writeOnlyStream = new WriteOnlyPipeStream(pipeWriter);
await writeOnlyStream.WriteAsync(new byte[10]);
stream.Position = 0;
var res = await ReadFromStreamAsByteArrayAsync(10, stream);
Assert.Equal(new byte[10], res);
}
[Fact]
public async Task CheckNestedStreamApi()
{
var stream = new MemoryStream();
Stream writeOnlyStream = stream;
for (var i = 0; i < 3; i++)
{
var pipeWriter = new StreamPipeWriter(writeOnlyStream);
writeOnlyStream = new WriteOnlyPipeStream(pipeWriter);
}
await writeOnlyStream.WriteAsync(new byte[10]);
stream.Position = 0;
var res = await ReadFromStreamAsByteArrayAsync(10, stream);
Assert.Equal(new byte[10], res);
}
[Fact]
public async Task WritesCanBeCanceledViaProvidedCancellationToken()
{
var writeOnlyStream = new WriteOnlyPipeStream(new HangingPipeWriter());
var pipeWriter = new StreamPipeWriter(writeOnlyStream);
var cts = new CancellationTokenSource(1);
await Assert.ThrowsAsync<TaskCanceledException>(async () => await pipeWriter.WriteAsync(new byte[1], cts.Token));
}
[Fact]
public async Task WriteCanBeCanceledViaCancelPendingFlushWhenFlushIsAsync()
{
var writeOnlyStream = new WriteOnlyPipeStream(new HangingPipeWriter());
var pipeWriter = new StreamPipeWriter(writeOnlyStream);
FlushResult flushResult = new FlushResult();
var tcs = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var task = Task.Run(async () =>
{
try
{
var writingTask = pipeWriter.WriteAsync(new byte[1]);
tcs.SetResult(0);
flushResult = await writingTask;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw ex;
}
});
await tcs.Task;
pipeWriter.CancelPendingFlush();
await task;
Assert.True(flushResult.IsCanceled);
}
private class HangingPipeWriter : PipeWriter
{
public override void Advance(int bytes)
{
}
public override void CancelPendingFlush()
{
throw new NotImplementedException();
}
public override void Complete(Exception exception = null)
{
throw new NotImplementedException();
}
public override async ValueTask<FlushResult> FlushAsync(CancellationToken cancellationToken = default)
{
await Task.Delay(30000, cancellationToken);
return new FlushResult();
}
public override Memory<byte> GetMemory(int sizeHint = 0)
{
return new Memory<byte>(new byte[4096]);
}
public override Span<byte> GetSpan(int sizeHint = 0)
{
return new Span<byte>(new byte[4096]);
}
public override void OnReaderCompleted(Action<Exception, object> callback, object state)
{
throw new NotImplementedException();
}
}
}
}

View File

@ -352,12 +352,12 @@ namespace Microsoft.AspNetCore.Identity.InMemory
}
else if (req.Path == new PathString("/me"))
{
Describe(res, AuthenticateResult.Success(new AuthenticationTicket(context.User, null, "Application")));
await DescribeAsync(res, AuthenticateResult.Success(new AuthenticationTicket(context.User, null, "Application")));
}
else if (req.Path.StartsWithSegments(new PathString("/me"), out remainder))
{
var auth = await context.AuthenticateAsync(remainder.Value.Substring(1));
Describe(res, auth);
await DescribeAsync(res, auth);
}
else if (req.Path == new PathString("/testpath") && testpath != null)
{
@ -393,7 +393,7 @@ namespace Microsoft.AspNetCore.Identity.InMemory
return server;
}
private static void Describe(HttpResponse res, AuthenticateResult result)
private static async Task DescribeAsync(HttpResponse res, AuthenticateResult result)
{
res.StatusCode = 200;
res.ContentType = "text/xml";
@ -412,7 +412,7 @@ namespace Microsoft.AspNetCore.Identity.InMemory
{
xml.WriteTo(writer);
}
res.Body.Write(memory.ToArray(), 0, memory.ToArray().Length);
await res.Body.WriteAsync(memory.ToArray(), 0, memory.ToArray().Length);
}
}

View File

@ -25,9 +25,7 @@ namespace SampleDestination
context.Response.ContentType = "text/plain; charset=utf-8";
context.Response.ContentLength = content.Length;
context.Response.Body.Write(content, 0, content.Length);
return Task.CompletedTask;
return context.Response.Body.WriteAsync(content, 0, content.Length);
}
}
}

View File

@ -86,9 +86,7 @@ namespace SampleDestination
context.Response.ContentType = "text/plain; charset=utf-8";
context.Response.ContentLength = content.Length;
context.Response.Body.Write(content, 0, content.Length);
return Task.CompletedTask;
return context.Response.Body.WriteAsync(content, 0, content.Length);
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
@ -81,6 +81,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
var uniqueId = Guid.NewGuid().ToString();
if (TestRequestDelegate(context, uniqueId))
{
var feature = context.Features.Get<IHttpBodyControlFeature>();
if (feature != null)
{
feature.AllowSynchronousIO = true;
}
context.Response.Write(uniqueId);
}
return Task.CompletedTask;

View File

@ -548,6 +548,12 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
app.UseResponseCompression();
app.Run(context =>
{
var feature = context.Features.Get<IHttpBodyControlFeature>();
if (feature != null)
{
feature.AllowSynchronousIO = true;
}
context.Response.Headers[HeaderNames.ContentMD5] = "MD5";
context.Response.ContentType = TextPlain;
context.Response.Body.Write(new byte[10], 0, 10);
@ -652,6 +658,12 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
context.Response.ContentType = TextPlain;
context.Features.Get<IHttpBufferingFeature>()?.DisableResponseBuffering();
var feature = context.Features.Get<IHttpBodyControlFeature>();
if (feature != null)
{
feature.AllowSynchronousIO = true;
}
foreach (var signal in responseReceived)
{
context.Response.Body.Write(new byte[1], 0, 1);

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Text;
@ -31,6 +31,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions
if (!string.IsNullOrEmpty(StatusDescription))
{
var feature = context.HttpContext.Features.Get<IHttpBodyControlFeature>();
if (feature != null)
{
feature.AllowSynchronousIO = true;
}
var content = Encoding.UTF8.GetBytes(StatusDescription);
response.ContentLength = content.Length;
response.ContentType = "text/plain; charset=utf-8";
@ -42,4 +47,4 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions
context.Logger?.CustomResponse(context.HttpContext.Request.GetEncodedUrl());
}
}
}
}

View File

@ -26,6 +26,28 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
public HttpClient Client { get; }
[Theory]
[InlineData("http://localhost/Login/Index", "Login", "Index", "http://localhost/Login")]
[InlineData("http://localhost/Login/Sso", "Login", "Sso", "http://localhost/Login/Sso")]
[InlineData("http://localhost/Contact/Index", "Contact", "Index", "http://localhost/Contact")]
[InlineData("http://localhost/Contact/Sso", "Contact", "Sso", "http://localhost/Contact/Sso")]
public async Task ConventionalRoutedAction_RouteUrl_AmbientValues(string requestUrl, string controller, string action, string expectedUrl)
{
// Arrange & Act
var response = await Client.GetAsync(requestUrl);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var body = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<RoutingResult>(body);
Assert.Equal(controller, result.Controller);
Assert.Equal(action, result.Action);
Assert.Equal(expectedUrl, Assert.Single(result.ExpectedUrls));
}
[Fact]
public async Task ConventionalRoutedAction_RouteContainsPage_RouteNotMatched()
{

View File

@ -0,0 +1,28 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Mvc;
namespace RoutingWebSite
{
// This controller is reachable via traditional routing.
public class ContactController : Controller
{
private readonly TestResponseGenerator _generator;
public ContactController(TestResponseGenerator generator)
{
_generator = generator;
}
public IActionResult Index()
{
return _generator.Generate(Url.RouteUrl("ActionAsMethod", null, Url.ActionContext.HttpContext.Request.Scheme));
}
public IActionResult Sso()
{
return _generator.Generate(Url.RouteUrl("ActionAsMethod", null, Url.ActionContext.HttpContext.Request.Scheme));
}
}
}

View File

@ -0,0 +1,28 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Mvc;
namespace RoutingWebSite
{
// This controller is reachable via traditional routing.
public class LoginController : Controller
{
private readonly TestResponseGenerator _generator;
public LoginController(TestResponseGenerator generator)
{
_generator = generator;
}
public IActionResult Index()
{
return _generator.Generate(Url.RouteUrl("ActionAsMethod", null, Url.ActionContext.HttpContext.Request.Scheme));
}
public IActionResult Sso()
{
return _generator.Generate(Url.RouteUrl("ActionAsMethod", null, Url.ActionContext.HttpContext.Request.Scheme));
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
@ -92,5 +92,10 @@ namespace Microsoft.AspNetCore.Authentication
{
return new HandleRequestResult() { Skipped = true };
}
public new static HandleRequestResult NoResult()
{
return new HandleRequestResult() { None = true };
}
}
}

View File

@ -283,7 +283,7 @@ namespace Microsoft.AspNetCore.Authentication
return HandleRequestResult.Handle();
}
return HandleRequestResult.Fail("Access was denied by the resource owner or by the remote server.", properties);
return HandleRequestResult.NoResult();
}
}
}
}

View File

@ -71,7 +71,9 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
// Visit https://tools.ietf.org/html/rfc6749#section-4.1.2.1 for more information.
if (StringValues.Equals(error, "access_denied"))
{
return await HandleAccessDeniedErrorAsync(properties);
var result = await HandleAccessDeniedErrorAsync(properties);
return !result.None ? result
: HandleRequestResult.Fail("Access was denied by the resource owner or by the remote server.", properties);
}
var failureMessage = new StringBuilder();

View File

@ -560,7 +560,11 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
// Visit https://tools.ietf.org/html/rfc6749#section-4.1.2.1 for more information.
if (string.Equals(authorizationResponse.Error, "access_denied", StringComparison.Ordinal))
{
return await HandleAccessDeniedErrorAsync(properties);
var result = await HandleAccessDeniedErrorAsync(properties);
if (!result.None)
{
return result;
}
}
return HandleRequestResult.Fail(CreateOpenIdConnectProtocolException(authorizationResponse, response: null), properties);

View File

@ -62,7 +62,9 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
// approve the authorization demand requested by the remote authorization server.
// Since it's a frequent scenario (that is not caused by incorrect configuration),
// denied errors are handled differently using HandleAccessDeniedErrorAsync().
return await HandleAccessDeniedErrorAsync(properties);
var result = await HandleAccessDeniedErrorAsync(properties);
return !result.None ? result
: HandleRequestResult.Fail("Access was denied by the resource owner or by the remote server.", properties);
}
var returnedToken = query["oauth_token"];
@ -311,4 +313,4 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
}
}
}
}
}

View File

@ -1302,7 +1302,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
app.Use(async (context, next) =>
{
var result = await context.AuthenticateAsync("Cookies");
Describe(context.Response, result);
await DescribeAsync(context.Response, result);
});
})
.ConfigureServices(services => services.AddAuthentication().AddCookie("Cookies", o =>
@ -1478,12 +1478,12 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
}
else if (req.Path == new PathString("/me"))
{
Describe(res, AuthenticateResult.Success(new AuthenticationTicket(context.User, new AuthenticationProperties(), CookieAuthenticationDefaults.AuthenticationScheme)));
await DescribeAsync(res, AuthenticateResult.Success(new AuthenticationTicket(context.User, new AuthenticationProperties(), CookieAuthenticationDefaults.AuthenticationScheme)));
}
else if (req.Path.StartsWithSegments(new PathString("/me"), out remainder))
{
var ticket = await context.AuthenticateAsync(remainder.Value.Substring(1));
Describe(res, ticket);
await DescribeAsync(res, ticket);
}
else if (req.Path == new PathString("/testpath") && testpath != null)
{
@ -1510,7 +1510,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
return server;
}
private static void Describe(HttpResponse res, AuthenticateResult result)
private static Task DescribeAsync(HttpResponse res, AuthenticateResult result)
{
res.StatusCode = 200;
res.ContentType = "text/xml";
@ -1524,7 +1524,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
xml.Add(result.Ticket.Properties.Items.Select(extra => new XElement("extra", new XAttribute("type", extra.Key), new XAttribute("value", extra.Value))));
}
var xmlBytes = Encoding.UTF8.GetBytes(xml.ToString());
res.Body.Write(xmlBytes, 0, xmlBytes.Length);
return res.Body.WriteAsync(xmlBytes, 0, xmlBytes.Length);
}
private static async Task<Transaction> SendAsync(TestServer server, string uri, string cookieHeader = null)

View File

@ -145,7 +145,7 @@ namespace Microsoft.AspNetCore.Authentication
{
var name = (remainder.Value.Length > 0) ? remainder.Value.Substring(1) : null;
var result = await context.AuthenticateAsync(name);
res.Describe(result?.Ticket?.Principal);
await res.DescribeAsync(result?.Ticket?.Principal);
}
else if (req.Path.StartsWithSegments(new PathString("/remove"), out remainder))
{

View File

@ -1177,26 +1177,26 @@ namespace Microsoft.AspNetCore.Authentication.Google
{
var result = await context.AuthenticateAsync(TestExtensions.CookieAuthenticationScheme);
var tokens = result.Properties.GetTokens();
res.Describe(tokens);
await res.DescribeAsync(tokens);
}
else if (req.Path == new PathString("/me"))
{
res.Describe(context.User);
await res.DescribeAsync(context.User);
}
else if (req.Path == new PathString("/authenticate"))
{
var result = await context.AuthenticateAsync(TestExtensions.CookieAuthenticationScheme);
res.Describe(result.Principal);
await res.DescribeAsync(result.Principal);
}
else if (req.Path == new PathString("/authenticateGoogle"))
{
var result = await context.AuthenticateAsync("Google");
res.Describe(result?.Principal);
await res.DescribeAsync(result?.Principal);
}
else if (req.Path == new PathString("/authenticateFacebook"))
{
var result = await context.AuthenticateAsync("Facebook");
res.Describe(result?.Principal);
await res.DescribeAsync(result?.Principal);
}
else if (req.Path == new PathString("/unauthorized"))
{

View File

@ -270,7 +270,7 @@ namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount
}
else if (req.Path == new PathString("/me"))
{
res.Describe(context.User);
await res.DescribeAsync(context.User);
}
else if (req.Path == new PathString("/signIn"))
{

View File

@ -469,7 +469,7 @@ namespace Microsoft.AspNetCore.Authentication
{
var name = (remainder.Value.Length > 0) ? remainder.Value.Substring(1) : null;
var result = await context.AuthenticateAsync(name);
res.Describe(result?.Ticket?.Principal);
await res.DescribeAsync(result?.Ticket?.Principal);
}
else
{

View File

@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Authentication
return transaction;
}
public static void Describe(this HttpResponse res, ClaimsPrincipal principal)
public static Task DescribeAsync(this HttpResponse res, ClaimsPrincipal principal)
{
res.StatusCode = 200;
res.ContentType = "text/xml";
@ -62,10 +62,10 @@ namespace Microsoft.AspNetCore.Authentication
}
}
var xmlBytes = Encoding.UTF8.GetBytes(xml.ToString());
res.Body.Write(xmlBytes, 0, xmlBytes.Length);
return res.Body.WriteAsync(xmlBytes, 0, xmlBytes.Length);
}
public static void Describe(this HttpResponse res, IEnumerable<AuthenticationToken> tokens)
public static Task DescribeAsync(this HttpResponse res, IEnumerable<AuthenticationToken> tokens)
{
res.StatusCode = 200;
res.ContentType = "text/xml";
@ -79,7 +79,7 @@ namespace Microsoft.AspNetCore.Authentication
}
}
var xmlBytes = Encoding.UTF8.GetBytes(xml.ToString());
res.Body.Write(xmlBytes, 0, xmlBytes.Length);
return res.Body.WriteAsync(xmlBytes, 0, xmlBytes.Length);
}
}

View File

@ -45,24 +45,5 @@ namespace Microsoft.AspNetCore.CookiePolicy
}
return transaction;
}
public static void Describe(this HttpResponse res, ClaimsPrincipal principal)
{
res.StatusCode = 200;
res.ContentType = "text/xml";
var xml = new XElement("xml");
if (principal != null)
{
foreach (var identity in principal.Identities)
{
xml.Add(identity.Claims.Select(claim =>
new XElement("claim", new XAttribute("type", claim.Type),
new XAttribute("value", claim.Value),
new XAttribute("issuer", claim.Issuer))));
}
}
var xmlBytes = Encoding.UTF8.GetBytes(xml.ToString());
res.Body.Write(xmlBytes, 0, xmlBytes.Length);
}
}
}

View File

@ -353,6 +353,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener
context = await server.AcceptAsync(Utilities.DefaultTimeout).Before(responseTask);
// First write sends headers
context.AllowSynchronousIO = true;
context.Response.Body.Write(new byte[10], 0, 10);
var response = await responseTask;

View File

@ -307,7 +307,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.FunctionalTests
httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString();
httpContext.Response.Headers["Cache-Control"] = "public, max-age=10";
httpContext.Response.ContentLength = 10;
httpContext.Response.Body.Flush();
httpContext.Response.Body.FlushAsync();
return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10);
}))
{

View File

@ -214,9 +214,7 @@ try
DWORD dwBufferSize = s_initialGetNativeSearchDirectoriesBufferSize;
DWORD dwRequiredBufferSize = 0;
RETURN_LAST_ERROR_IF_NULL(m_hHostFxrDll = LoadLibraryW(hostfxrOptions.GetHostFxrLocation().c_str()));
auto const hostFxr = HostFxr::CreateFromLoadedModule();
m_hHostFxrDll.Load(hostfxrOptions.GetHostFxrLocation());
{
auto redirectionOutput = LoggingHelpers::CreateOutputs(
@ -227,7 +225,7 @@ try
);
StandardStreamRedirection stdOutRedirection(*redirectionOutput.get(), m_pServer.IsCommandLineLaunch());
auto hostFxrErrorRedirection = hostFxr.RedirectOutput(redirectionOutput.get());
auto hostFxrErrorRedirection = m_hHostFxrDll.RedirectOutput(redirectionOutput.get());
struNativeSearchPaths.resize(dwBufferSize);
while (TRUE)
@ -237,7 +235,7 @@ try
hostfxrOptions.GetArguments(hostfxrArgc, hostfxrArgv);
const auto intHostFxrExitCode = hostFxr.GetNativeSearchDirectories(
const auto intHostFxrExitCode = m_hHostFxrDll.GetNativeSearchDirectories(
hostfxrArgc,
hostfxrArgv.get(),
struNativeSearchPaths.data(),

View File

@ -10,6 +10,7 @@
#include "HandleWrapper.h"
#include "ApplicationFactory.h"
#include "RedirectionOutput.h"
#include "HostFxr.h"
class HandlerResolver
{
@ -35,7 +36,7 @@ private:
SRWLOCK m_requestHandlerLoadLock {};
std::wstring m_loadedApplicationId;
APP_HOSTING_MODEL m_loadedApplicationHostingModel;
HandleWrapper<ModuleHandleTraits> m_hHostFxrDll;
HostFxr m_hHostFxrDll;
static const PCWSTR s_pwzAspnetcoreInProcessRequestHandlerName;
static const PCWSTR s_pwzAspnetcoreOutOfProcessRequestHandlerName;

View File

@ -30,6 +30,61 @@ void HostFxrErrorRedirector::HostFxrErrorRedirectorCallback(const WCHAR* message
m_writeFunction->Append(std::wstring(message) + L"\r\n");
}
void HostFxr::Load()
{
HMODULE hModule;
THROW_LAST_ERROR_IF(!GetModuleHandleEx(0, L"hostfxr.dll", &hModule));
Load(hModule);
}
void HostFxr::Load(HMODULE moduleHandle)
{
m_hHostFxrDll = moduleHandle;
try
{
m_hostfxr_main_fn = ModuleHelpers::GetKnownProcAddress<hostfxr_main_fn>(moduleHandle, "hostfxr_main");
m_hostfxr_get_native_search_directories_fn = ModuleHelpers::GetKnownProcAddress<hostfxr_get_native_search_directories_fn>(moduleHandle, "hostfxr_get_native_search_directories");
m_corehost_set_error_writer_fn = ModuleHelpers::GetKnownProcAddress<corehost_set_error_writer_fn>(moduleHandle, "hostfxr_set_error_writer", /* optional */ true);
}
catch (...)
{
EventLog::Error(
ASPNETCORE_EVENT_GENERAL_ERROR,
ASPNETCORE_EVENT_HOSTFXR_DLL_INVALID_VERSION_MSG,
ModuleHelpers::GetModuleFileNameValue(moduleHandle).c_str()
);
throw;
}
}
void HostFxr::Load(const std::wstring& location)
{
try
{
HMODULE hModule;
THROW_LAST_ERROR_IF_NULL(hModule = LoadLibraryW(location.c_str()));
Load(hModule);
}
catch (...)
{
EventLog::Error(
ASPNETCORE_EVENT_GENERAL_ERROR,
ASPNETCORE_EVENT_HOSTFXR_DLL_UNABLE_TO_LOAD_MSG,
location.c_str()
);
throw;
}
}
void HostFxr::SetMain(hostfxr_main_fn hostfxr_main_fn)
{
m_hostfxr_main_fn = hostfxr_main_fn;
}
int HostFxr::Main(DWORD argc, const PCWSTR* argv) const noexcept(false)
{
return m_hostfxr_main_fn(argc, argv);
@ -44,27 +99,3 @@ HostFxrErrorRedirector HostFxr::RedirectOutput(RedirectionOutput* writer) const
{
return HostFxrErrorRedirector(m_corehost_set_error_writer_fn, writer);
}
HostFxr HostFxr::CreateFromLoadedModule()
{
HMODULE hModule;
THROW_LAST_ERROR_IF_NULL(hModule = GetModuleHandle(L"hostfxr.dll"));
try
{
return HostFxr(
ModuleHelpers::GetKnownProcAddress<hostfxr_main_fn>(hModule, "hostfxr_main"),
ModuleHelpers::GetKnownProcAddress<hostfxr_get_native_search_directories_fn>(hModule, "hostfxr_get_native_search_directories"),
ModuleHelpers::GetKnownProcAddress<corehost_set_error_writer_fn>(hModule, "hostfxr_set_error_writer", /* optional */ true));
}
catch (...)
{
EventLog::Error(
ASPNETCORE_EVENT_GENERAL_ERROR,
ASPNETCORE_EVENT_HOSTFXR_DLL_INVALID_VERSION_MSG,
ModuleHelpers::GetModuleFileNameValue(hModule).c_str()
);
throw;
}
}

View File

@ -26,9 +26,13 @@ private:
static inline thread_local RedirectionOutput* m_writeFunction;
};
class HostFxr
class HostFxr: NonCopyable
{
public:
HostFxr() : HostFxr(nullptr, nullptr, nullptr)
{
}
HostFxr(
hostfxr_main_fn hostfxr_main_fn,
hostfxr_get_native_search_directories_fn hostfxr_get_native_search_directories_fn,
@ -39,18 +43,22 @@ public:
{
}
void Load();
void Load(HMODULE moduleHandle);
void Load(const std::wstring& location);
~HostFxr() = default;
void SetMain(hostfxr_main_fn hostfxr_main_fn);
int Main(DWORD argc, CONST PCWSTR* argv) const noexcept(false);
int GetNativeSearchDirectories(INT argc, CONST PCWSTR* argv, PWSTR buffer, DWORD buffer_size, DWORD* required_buffer_size) const noexcept;
HostFxrErrorRedirector RedirectOutput(RedirectionOutput* writer) const noexcept;
static
HostFxr CreateFromLoadedModule();
private:
HandleWrapper<ModuleHandleTraits> m_hHostFxrDll;
hostfxr_main_fn m_hostfxr_main_fn;
hostfxr_get_native_search_directories_fn m_hostfxr_get_native_search_directories_fn;
corehost_set_error_writer_fn m_corehost_set_error_writer_fn;

View File

@ -39,6 +39,7 @@
#define ASPNETCORE_EVENT_RECYCLE_FAILURE_CONFIGURATION_MSG L"Failed to recycle application due to a configuration change at '%s'. Recycling worker process."
#define ASPNETCORE_EVENT_MODULE_DISABLED_MSG L"AspNetCore Module is disabled"
#define ASPNETCORE_EVENT_HOSTFXR_DLL_INVALID_VERSION_MSG L"Hostfxr version used does not support 'hostfxr_get_native_search_directories', update the version of hostfxr to a higher version. Path to hostfxr: '%s'."
#define ASPNETCORE_EVENT_HOSTFXR_DLL_UNABLE_TO_LOAD_MSG L"Unable to load '%s'. This might be caused by a bitness mismatch between IIS application pool and published application."
#define ASPNETCORE_EVENT_HOSTFXR_FAILURE_MSG L"Invoking hostfxr to find the inprocess request handler failed without finding any native dependencies. This most likely means the app is misconfigured, please check the versions of Microsoft.NetCore.App and Microsoft.AspNetCore.App that are targeted by the application and are installed on the machine."
#define ASPNETCORE_EVENT_INPROCESS_THREAD_EXCEPTION_MSG L"Application '%s' with physical root '%s' hit unexpected managed exception, exception code = '0x%x'. Please check the stderr logs for more information."
#define ASPNETCORE_EVENT_INPROCESS_THREAD_EXCEPTION_STDOUT_MSG L"Application '%s' with physical root '%s' hit unexpected managed exception, exception code = '0x%x'. Last 4KB characters of captured stdout and stderr logs:\r\n%s"

View File

@ -189,11 +189,11 @@ IN_PROCESS_APPLICATION::ExecuteApplication()
hostFxrResolutionResult->GetArguments(context->m_argc, context->m_argv);
THROW_IF_FAILED(SetEnvironmentVariablesOnWorkerProcess());
context->m_hostFxr = HostFxr::CreateFromLoadedModule();
context->m_hostFxr.Load();
}
else
{
context->m_hostFxr = HostFxr(s_fMainCallback, nullptr, nullptr);
context->m_hostFxr.SetMain(s_fMainCallback);
}
// There can only ever be a single instance of .NET Core

View File

@ -82,6 +82,8 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
_options = options;
_server = server;
_logger = logger;
((IHttpBodyControlFeature)this).AllowSynchronousIO = _options.AllowSynchronousIO;
}
public Version HttpVersion { get; set; }

View File

@ -1,10 +1,20 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Builder
{
public class IISServerOptions
{
/// <summary>
/// Gets or sets a value that controls whether synchronous IO is allowed for the <see cref="HttpContext.Request"/> and <see cref="HttpContext.Response"/>
/// </summary>
/// <remarks>
/// Defaults to true.
/// </remarks>
public bool AllowSynchronousIO { get; set; } = true;
/// <summary>
/// If true the server should set HttpContext.User. If false the server will only provide an
/// identity when explicitly requested by the AuthenticationScheme.

View File

@ -81,10 +81,10 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("identity", 0));
client.DefaultRequestHeaders.Add("Response-Content-Type", "text/event-stream");
var messages = "Message1\r\nMessage2\r\n";
var messages = "Message1\r\nMessage2\r\n\r\n";
// Send messages with terminator
var response = await client.PostAsync("ReadAndWriteEchoLines", new StringContent(messages + "\r\n"));
var response = await client.PostAsync("ReadAndWriteEchoLines", new StringContent(messages));
Assert.Equal(messages, await response.Content.ReadAsStringAsync());
Assert.True(response.Content.Headers.TryGetValues("Content-Type", out var contentTypes));
Assert.Single(contentTypes, "text/event-stream");

View File

@ -110,6 +110,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
[ConditionalTheory]
[InlineData(RuntimeArchitecture.x64)]
[InlineData(RuntimeArchitecture.x86)]
[SkipIfNotAdmin]
[RequiresNewShim]
[RequiresIIS(IISCapability.PoolEnvironmentVariables)]
public async Task StartsWithDotnetInstallLocation(RuntimeArchitecture runtimeArchitecture)
@ -256,7 +257,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
}
[ConditionalFact]
public async Task RemoveHostfxrFromApp_InProcessHostfxrInvalid()
public async Task RemoveHostfxrFromApp_InProcessHostfxrAPIAbsent()
{
var deploymentParameters = _fixture.GetBaseDeploymentParameters(_fixture.InProcessTestSite, publish: true);
deploymentParameters.ApplicationType = ApplicationType.Standalone;
@ -271,6 +272,20 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
EventLogHelpers.VerifyEventLogEvent(deploymentResult, EventLogHelpers.InProcessHostfxrInvalid(deploymentResult), Logger);
}
[ConditionalFact]
public async Task RemoveHostfxrFromApp_InProcessHostfxrLoadFailure()
{
var deploymentParameters = _fixture.GetBaseDeploymentParameters(_fixture.InProcessTestSite, publish: true);
deploymentParameters.ApplicationType = ApplicationType.Standalone;
var deploymentResult = await DeployAsync(deploymentParameters);
// We don't distinguish between load failure types so making dll empty should be enough
File.WriteAllText(Path.Combine(deploymentResult.ContentRoot, "hostfxr.dll"), "");
await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult);
EventLogHelpers.VerifyEventLogEvent(deploymentResult, EventLogHelpers.InProcessHostfxrUnableToLoad(deploymentResult), Logger);
}
[ConditionalFact]
public async Task TargedDifferenceSharedFramework_FailedToFindNativeDependencies()
{

View File

@ -185,6 +185,11 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
return $"Hostfxr version used does not support 'hostfxr_get_native_search_directories', update the version of hostfxr to a higher version. Path to hostfxr: '(.*)'.";
}
public static string InProcessHostfxrUnableToLoad(IISDeploymentResult deploymentResult)
{
return $"Unable to load '(.*)'. This might be caused by a bitness mismatch between IIS application pool and published application.";
}
public static string InProcessFailedToFindNativeDependencies(IISDeploymentResult deploymentResult)
{
return "Invoking hostfxr to find the inprocess request handler failed without finding any native dependencies. " +

View File

@ -331,10 +331,10 @@ namespace TestSite
await ctx.Response.Body.FlushAsync();
var reader = new StreamReader(ctx.Request.Body);
while (!reader.EndOfStream)
while (true)
{
var line = await reader.ReadLineAsync();
if (line == "")
if (line == null)
{
return;
}
@ -357,10 +357,10 @@ namespace TestSite
await ctx.Response.Body.FlushAsync();
var reader = new StreamReader(ctx.Request.Body);
while (!reader.EndOfStream)
while (true)
{
var line = await reader.ReadLineAsync();
if (line == "")
if (line == null)
{
return;
}
@ -438,8 +438,8 @@ namespace TestSite
private async Task TestReadOffsetWorks(HttpContext ctx)
{
var buffer = new byte[11];
ctx.Request.Body.Read(buffer, 0, 6);
ctx.Request.Body.Read(buffer, 6, 5);
await ctx.Request.Body.ReadAsync(buffer, 0, 6);
await ctx.Request.Body.ReadAsync(buffer, 6, 5);
await ctx.Response.WriteAsync(Encoding.UTF8.GetString(buffer));
}

View File

@ -68,7 +68,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
{
var task = ReadAsync(buffer, offset, count, default(CancellationToken), state);
var task = ReadAsync(buffer, offset, count, default, state);
if (callback != null)
{
task.ContinueWith(t => callback.Invoke(t));

View File

@ -37,7 +37,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
public override void Flush()
{
FlushAsync(default(CancellationToken)).GetAwaiter().GetResult();
FlushAsync(default).GetAwaiter().GetResult();
}
public override Task FlushAsync(CancellationToken cancellationToken)
@ -64,12 +64,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
throw new InvalidOperationException(CoreStrings.SynchronousWritesDisallowed);
}
WriteAsync(buffer, offset, count, default(CancellationToken)).GetAwaiter().GetResult();
WriteAsync(buffer, offset, count, default).GetAwaiter().GetResult();
}
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
{
var task = WriteAsync(buffer, offset, count, default(CancellationToken), state);
var task = WriteAsync(buffer, offset, count, default, state);
if (callback != null)
{
task.ContinueWith(t => callback.Invoke(t));

View File

@ -61,7 +61,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
try
{
if (!readableBuffer.IsEmpty)
if (readableBufferLength != 0)
{
// buffer.Length is int
actual = (int)Math.Min(readableBufferLength, buffer.Length);
@ -69,8 +69,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
// Make sure we don't double-count bytes on the next read.
_alreadyTimedBytes = readableBufferLength - actual;
var slice = readableBuffer.Slice(0, actual);
consumed = readableBuffer.GetPosition(actual);
var slice = actual == readableBufferLength ? readableBuffer : readableBuffer.Slice(0, actual);
consumed = slice.End;
slice.CopyTo(buffer.Span);
return actual;
@ -106,7 +106,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
try
{
if (!readableBuffer.IsEmpty)
if (readableBufferLength != 0)
{
foreach (var memory in readableBuffer)
{

Some files were not shown because too many files have changed in this diff Show More