diff --git a/.gitignore b/.gitignore index 0ce0bf24e6..8a2385174b 100644 --- a/.gitignore +++ b/.gitignore @@ -39,4 +39,4 @@ modules/ launchSettings.json msbuild.ProjectImports.zip StyleCop.Cache -UpgradeLog.htm \ No newline at end of file +UpgradeLog.htm diff --git a/Directory.Build.targets b/Directory.Build.targets index 9f6393d132..3f3ff318a9 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -125,6 +125,11 @@ $(NETStandardLibraryRefPackageVersion) + + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 032e908c2a..9fd316a747 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -420,5 +420,9 @@ https://github.com/aspnet/Extensions 0538d10f82468dd7539d9abdb7b60c378989e0a6 + + https://github.com/dotnet/roslyn + c91adff42c488aef2c2c532a7b053fb55e0c16ea + diff --git a/eng/Versions.props b/eng/Versions.props index 42b023948f..e69b75350c 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -33,8 +33,6 @@ true - - true true @@ -53,6 +51,8 @@ 1.0.0-beta.19323.4 + + 3.3.0-beta1-19351-01 3.0.0-preview8-27903-07 3.0.0-preview8-27903-07 @@ -217,7 +217,7 @@ 4.2.1 4.2.1 3.8.0 - 0.1.22-pre1 + 0.1.22-pre2 3.0.0-preview3.4 3.0.0-preview3.4 3.0.0-preview3.4 @@ -255,6 +255,10 @@ https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json; https://grpc.jfrog.io/grpc/api/nuget/v3/grpc-nuget-dev; + + $(RestoreSources); + https://dotnet.myget.org/F/roslyn/api/v3/index.json; + $(RestoreSources); diff --git a/src/Mvc/Mvc.DataAnnotations/test/DataAnnotationsMetadataProviderTest.cs b/src/Mvc/Mvc.DataAnnotations/test/DataAnnotationsMetadataProviderTest.cs index e3fa20042a..2d260405ef 100644 --- a/src/Mvc/Mvc.DataAnnotations/test/DataAnnotationsMetadataProviderTest.cs +++ b/src/Mvc/Mvc.DataAnnotations/test/DataAnnotationsMetadataProviderTest.cs @@ -1142,7 +1142,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations Assert.Equal(initialValue, context.ValidationMetadata.IsRequired); } - [Fact] + [Fact(Skip = "https://github.com/aspnet/AspNetCore/issues/11828")] public void CreateValidationMetadata_InfersRequiredAttribute_NoNonNullableProperty() { // Arrange @@ -1325,7 +1325,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations Assert.Same(attribute, validatorMetadata); } - [Fact] + [Fact(Skip = "https://github.com/aspnet/AspNetCore/issues/11828")] public void IsNonNullable_FindsNonNullableProperty() { // Arrange @@ -1353,7 +1353,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations Assert.False(result); } - [Fact] + [Fact(Skip = "https://github.com/aspnet/AspNetCore/issues/11828")] public void IsNonNullable_FindsNonNullableParameter() { // Arrange diff --git a/src/Mvc/test/Mvc.FunctionalTests/NonNullableReferenceTypesTest.cs b/src/Mvc/test/Mvc.FunctionalTests/NonNullableReferenceTypesTest.cs index e22462ce34..052b180d2d 100644 --- a/src/Mvc/test/Mvc.FunctionalTests/NonNullableReferenceTypesTest.cs +++ b/src/Mvc/test/Mvc.FunctionalTests/NonNullableReferenceTypesTest.cs @@ -26,7 +26,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests private HttpClient Client { get; set; } - [Fact] + [Fact(Skip = "https://github.com/aspnet/AspNetCore/issues/11828")] public async Task CanUseNonNullableReferenceType_WithController_OmitData_ValidationErrors() { // Arrange diff --git a/src/Mvc/test/Mvc.IntegrationTests/NullableReferenceTypeIntegrationTest.cs b/src/Mvc/test/Mvc.IntegrationTests/NullableReferenceTypeIntegrationTest.cs index 6e61419fe3..808f37cf61 100644 --- a/src/Mvc/test/Mvc.IntegrationTests/NullableReferenceTypeIntegrationTest.cs +++ b/src/Mvc/test/Mvc.IntegrationTests/NullableReferenceTypeIntegrationTest.cs @@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests } #nullable restore - [Fact] + [Fact(Skip = "https://github.com/aspnet/AspNetCore/issues/11828")] public async Task BindProperty_WithNonNullableReferenceType_NoData_ValidationError() { // Arrange @@ -112,7 +112,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests } #nullable restore - [Fact] + [Fact(Skip = "https://github.com/aspnet/AspNetCore/issues/11828")] public async Task BindProperty_WithNonNullableReferenceType_NoData_ValidationError_CustomMessage() { // Arrange @@ -159,7 +159,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests } #nullable restore - [Fact] + [Fact(Skip = "https://github.com/aspnet/AspNetCore/issues/11828")] public async Task BindParameter_WithNonNullableReferenceType_NoData_ValidationError() { // Arrange diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/Properties/launchSettings.json b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/Properties/launchSettings.json index ac7538d34e..edbcd5873c 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/Properties/launchSettings.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/Properties/launchSettings.json @@ -3,7 +3,7 @@ "GrpcService-CSharp": { "commandName": "Project", "launchBrowser": false, - "applicationUrl": "https://localhost:50051", + "applicationUrl": "https://localhost:5001", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/appsettings.json b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/appsettings.json index 7cb5ac8193..efb26250e8 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/appsettings.json +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/appsettings.json @@ -5,5 +5,10 @@ "Microsoft.Hosting.Lifetime": "Information" } }, - "AllowedHosts": "*" + "AllowedHosts": "*", + "Kestrel": { + "EndpointDefaults": { + "Protocols": "Http2" + } + } } diff --git a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/ReactRedux-CSharp/Controllers/WeatherForecastController.cs b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/ReactRedux-CSharp/Controllers/WeatherForecastController.cs index 097eb58460..42f3485fc9 100644 --- a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/ReactRedux-CSharp/Controllers/WeatherForecastController.cs +++ b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/ReactRedux-CSharp/Controllers/WeatherForecastController.cs @@ -2,17 +2,11 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -#if (!NoAuth) -using Microsoft.AspNetCore.Authorization; -#endif using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; namespace Company.WebApplication1.Controllers { -#if (!NoAuth) - [Authorize] -#endif [ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase diff --git a/src/ProjectTemplates/test/SpaTemplateTest/ReactReduxTemplateTest.cs b/src/ProjectTemplates/test/SpaTemplateTest/ReactReduxTemplateTest.cs index 4462f784c2..44d6b67f32 100644 --- a/src/ProjectTemplates/test/SpaTemplateTest/ReactReduxTemplateTest.cs +++ b/src/ProjectTemplates/test/SpaTemplateTest/ReactReduxTemplateTest.cs @@ -3,8 +3,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.E2ETesting; -using Microsoft.AspNetCore.Testing; -using Microsoft.AspNetCore.Testing.xunit; using Templates.Test.Helpers; using Xunit; using Xunit.Abstractions; @@ -19,7 +17,6 @@ namespace Templates.Test.SpaTemplateTest } [Fact] - [Flaky("https://github.com/aspnet/AspNetCore-Internal/issues/2407", FlakyOn.AzP.Windows)] public Task ReactReduxTemplate_Works_NetCore() => SpaTemplateImplAsync("reactredux", "reactredux", useLocalDb: false, usesAuth: false); } diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/Http1OutputProducer.cs b/src/Servers/Kestrel/Core/src/Internal/Http/Http1OutputProducer.cs index c1ee388abf..a45a740950 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http/Http1OutputProducer.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http/Http1OutputProducer.cs @@ -55,7 +55,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http // and append the end terminator. private bool _autoChunk; - private bool _suffixSent; + + // We rely on the TimingPipeFlusher to give us ValueTasks that can be safely awaited multiple times. + private bool _writeStreamSuffixCalled; + private ValueTask _writeStreamSuffixValueTask; + private int _advancedBytesForChunk; private Memory _currentChunkMemory; private bool _currentChunkMemoryUpdated; @@ -113,15 +117,28 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http { lock (_contextLock) { - if (_suffixSent || !_autoChunk) + if (_writeStreamSuffixCalled) { - _suffixSent = true; - return FlushAsync(); + // If WriteStreamSuffixAsync has already been called, no-op and return the previously returned ValueTask. + return _writeStreamSuffixValueTask; } - _suffixSent = true; - var writer = new BufferWriter(_pipeWriter); - return WriteAsyncInternal(ref writer, EndChunkedResponseBytes); + if (_autoChunk) + { + var writer = new BufferWriter(_pipeWriter); + _writeStreamSuffixValueTask = WriteAsyncInternal(ref writer, EndChunkedResponseBytes); + } + else if (_unflushedBytes > 0) + { + _writeStreamSuffixValueTask = FlushAsync(); + } + else + { + _writeStreamSuffixValueTask = default; + } + + _writeStreamSuffixCalled = true; + return _writeStreamSuffixValueTask; } } @@ -510,7 +527,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http // Cleared in sequential address ascending order _currentMemoryPrefixBytes = 0; _autoChunk = false; - _suffixSent = false; + _writeStreamSuffixCalled = false; + _writeStreamSuffixValueTask = default; _currentChunkMemoryUpdated = false; _startCalled = false; } @@ -701,7 +719,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http [StackTraceHidden] private void ThrowIfSuffixSent() { - if (_suffixSent) + if (_writeStreamSuffixCalled) { throw new InvalidOperationException("Writing is not allowed after writer was completed."); } diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/ResponseTests.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/ResponseTests.cs index 005dfd8ad9..d1a6632edc 100644 --- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/ResponseTests.cs +++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/ResponseTests.cs @@ -2905,7 +2905,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests var expectedString = new string('a', expectedLength); await using (var server = new TestServer(async httpContext => { - httpContext.Response.Headers["Content-Length"] = new[] { expectedLength.ToString() }; + httpContext.Response.ContentLength = expectedLength; await httpContext.Response.WriteAsync(expectedString); Assert.True(httpContext.Response.HasStarted); }, testContext)) @@ -2927,6 +2927,55 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests } } + [Fact] + public async Task UnflushedContentLengthResponseIsFlushedAutomatically() + { + var testContext = new TestServiceContext(LoggerFactory); + var expectedLength = 100000; + var expectedString = new string('a', expectedLength); + + void WriteStringWithoutFlushing(PipeWriter writer, string content) + { + var encoder = Encoding.ASCII.GetEncoder(); + var encodedLength = Encoding.ASCII.GetByteCount(expectedString); + var source = expectedString.AsSpan(); + var completed = false; + + while (!completed) + { + encoder.Convert(source, writer.GetSpan(), flush: source.Length == 0, out var charsUsed, out var bytesUsed, out completed); + writer.Advance(bytesUsed); + source = source.Slice(charsUsed); + } + } + + await using (var server = new TestServer(httpContext => + { + httpContext.Response.ContentLength = expectedLength; + + WriteStringWithoutFlushing(httpContext.Response.BodyWriter, expectedString); + + Assert.False(httpContext.Response.HasStarted); + return Task.CompletedTask; + }, testContext)) + { + using (var connection = server.CreateConnection()) + { + await connection.Send( + "GET / HTTP/1.1", + "Host:", + "", + ""); + await connection.Receive( + "HTTP/1.1 200 OK", + $"Date: {testContext.DateHeaderValue}", + $"Content-Length: {expectedLength}", + "", + expectedString); + } + } + } + [Fact] public async Task StartAsyncAndFlushWorks() {