From 9e5feb6b56240866f0f2f8c8150c1602d7d1548a Mon Sep 17 00:00:00 2001 From: John Luo Date: Tue, 19 Feb 2019 20:06:48 -0800 Subject: [PATCH 01/14] Required changes for 3.0.0 preview3 --- .travis.yml | 2 +- examples/Server/Startup.cs | 4 +--- global.json | 2 +- perf/benchmarkapps/BenchmarkServer/Startup.cs | 4 +--- .../Internal/HttpContextServerCallContext.cs | 2 +- .../Internal/PipeExtensions.cs | 20 ++++++++++++++++++- ...GrpcEndpointRouteBuilderExtensionsTests.cs | 4 ++-- testassets/InteropTestsWebsite/Startup.cs | 8 +------- 8 files changed, 27 insertions(+), 19 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1a7758ef9..b23f6a490 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ branches: only: - master install: - - curl -o dotnet-sdk.tar.gz -sSL https://download.visualstudio.microsoft.com/download/pr/efa6dde9-a5ee-4322-b13c-a2a02d3980f0/dad445eba341c1d806bae5c8afb47015/dotnet-sdk-3.0.100-preview-010184-linux-x64.tar.gz + - curl -o dotnet-sdk.tar.gz -sSL https://dotnetcli.blob.core.windows.net/dotnet/Sdk/release/3.0.1xx/dotnet-sdk-latest-linux-x64.tar.gz - mkdir -p $PWD/dotnet - tar zxf dotnet-sdk.tar.gz -C $PWD/dotnet - export PATH="$PWD/dotnet:$PATH" diff --git a/examples/Server/Startup.cs b/examples/Server/Startup.cs index fa63e4449..8a7bd80f9 100644 --- a/examples/Server/Startup.cs +++ b/examples/Server/Startup.cs @@ -16,9 +16,7 @@ #endregion -using Grpc.AspNetCore; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; namespace GRPCServer @@ -34,7 +32,7 @@ public void ConfigureServices(IServiceCollection services) } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IHostingEnvironment env) + public void Configure(IApplicationBuilder app) { app.UseRouting(routes => { diff --git a/global.json b/global.json index e66ff4ebe..f660a138e 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "3.0.100-preview-010184" + "version": "3.0.100-preview3-010313" } } diff --git a/perf/benchmarkapps/BenchmarkServer/Startup.cs b/perf/benchmarkapps/BenchmarkServer/Startup.cs index c1b52ffb3..75ccb1ada 100644 --- a/perf/benchmarkapps/BenchmarkServer/Startup.cs +++ b/perf/benchmarkapps/BenchmarkServer/Startup.cs @@ -16,9 +16,7 @@ #endregion -using Grpc.AspNetCore; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; namespace BenchmarkServer @@ -33,7 +31,7 @@ public void ConfigureServices(IServiceCollection services) } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IHostingEnvironment env) + public void Configure(IApplicationBuilder app) { app.UseRouting(routes => { diff --git a/src/Grpc.AspNetCore.Server/Internal/HttpContextServerCallContext.cs b/src/Grpc.AspNetCore.Server/Internal/HttpContextServerCallContext.cs index 5aa98cdd9..355ce9862 100644 --- a/src/Grpc.AspNetCore.Server/Internal/HttpContextServerCallContext.cs +++ b/src/Grpc.AspNetCore.Server/Internal/HttpContextServerCallContext.cs @@ -199,7 +199,7 @@ protected override Task WriteResponseHeadersAsyncCore(Metadata responseHeaders) } } - return HttpContext.Response.Body.FlushAsync(); + return HttpContext.Response.StartAsync(); } public void Initialize() diff --git a/src/Grpc.AspNetCore.Server/Internal/PipeExtensions.cs b/src/Grpc.AspNetCore.Server/Internal/PipeExtensions.cs index ac0903ecd..4301af37f 100644 --- a/src/Grpc.AspNetCore.Server/Internal/PipeExtensions.cs +++ b/src/Grpc.AspNetCore.Server/Internal/PipeExtensions.cs @@ -55,6 +55,24 @@ public static Task WriteMessageAsync(this PipeWriter pipeWriter, byte[] messageD return Task.FromException(new RpcException(SendingMessageExceedsLimitStatus)); } + if (!serverCallContext.HttpContext.Response.HasStarted) + { + return pipeWriter.WriteMessageCoreInitialAsync(messageData, serverCallContext, flush); + } + + return pipeWriter.WriteMessageCoreAsync(messageData, serverCallContext, flush); + } + + private static async Task WriteMessageCoreInitialAsync(this PipeWriter pipeWriter, byte[] messageData, HttpContextServerCallContext serverCallContext, bool flush) + { + // Must call StartAsync before the first pipeWriter.GetSpan() in WriteHeader + await serverCallContext.HttpContext.Response.StartAsync(); + + await pipeWriter.WriteMessageCoreAsync(messageData, serverCallContext, flush); + } + + private static Task WriteMessageCoreAsync(this PipeWriter pipeWriter, byte[] messageData, HttpContextServerCallContext serverCallContext, bool flush) + { WriteHeader(pipeWriter, messageData.Length); pipeWriter.Write(messageData); @@ -77,7 +95,7 @@ public static Task WriteMessageAsync(this PipeWriter pipeWriter, byte[] messageD private static void WriteHeader(PipeWriter pipeWriter, int length) { - Span headerData = pipeWriter.GetSpan(HeaderSize); + var headerData = pipeWriter.GetSpan(HeaderSize); // Messages are currently always uncompressed headerData[0] = 0; EncodeMessageLength(length, headerData.Slice(1)); diff --git a/test/Grpc.AspNetCore.Server.Tests/GrpcEndpointRouteBuilderExtensionsTests.cs b/test/Grpc.AspNetCore.Server.Tests/GrpcEndpointRouteBuilderExtensionsTests.cs index 976e50adc..620c99716 100644 --- a/test/Grpc.AspNetCore.Server.Tests/GrpcEndpointRouteBuilderExtensionsTests.cs +++ b/test/Grpc.AspNetCore.Server.Tests/GrpcEndpointRouteBuilderExtensionsTests.cs @@ -78,11 +78,11 @@ public void MapGrpcService_CanBind_CreatesEndpoints() var routeEndpoint1 = (RouteEndpoint)endpoints[0]; Assert.AreEqual("/Greet.Greeter/SayHello", routeEndpoint1.RoutePattern.RawText); - Assert.AreEqual("POST", ((IHttpMethodMetadata)routeEndpoint1.Metadata.Single()).HttpMethods.Single()); + Assert.AreEqual("POST", ((IHttpMethodMetadata)routeEndpoint1.Metadata.Single(m => m is HttpMethodMetadata)).HttpMethods.Single()); var routeEndpoint2 = (RouteEndpoint)endpoints[1]; Assert.AreEqual("/Greet.Greeter/SayHellos", routeEndpoint2.RoutePattern.RawText); - Assert.AreEqual("POST", ((IHttpMethodMetadata)routeEndpoint2.Metadata.Single()).HttpMethods.Single()); + Assert.AreEqual("POST", ((IHttpMethodMetadata)routeEndpoint2.Metadata.Single(m => m is HttpMethodMetadata)).HttpMethods.Single()); } [Test] diff --git a/testassets/InteropTestsWebsite/Startup.cs b/testassets/InteropTestsWebsite/Startup.cs index ead9e2a58..6f7a9cfe7 100644 --- a/testassets/InteropTestsWebsite/Startup.cs +++ b/testassets/InteropTestsWebsite/Startup.cs @@ -16,15 +16,9 @@ #endregion -using Grpc.AspNetCore; using Grpc.Testing; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; -using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; namespace InteropTestsWebsite { @@ -38,7 +32,7 @@ public void ConfigureServices(IServiceCollection services) } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IHostingEnvironment env) + public void Configure(IApplicationBuilder app) { app.UseRouting(builder => { From 9fd48f6fa861fb8c91a02701db73a423130969ef Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Wed, 20 Feb 2019 11:20:24 -0800 Subject: [PATCH 02/14] Update test/Grpc.AspNetCore.Server.Tests/GrpcEndpointRouteBuilderExtensionsTests.cs Co-Authored-By: JunTaoLuo --- .../GrpcEndpointRouteBuilderExtensionsTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Grpc.AspNetCore.Server.Tests/GrpcEndpointRouteBuilderExtensionsTests.cs b/test/Grpc.AspNetCore.Server.Tests/GrpcEndpointRouteBuilderExtensionsTests.cs index 620c99716..69eb3f989 100644 --- a/test/Grpc.AspNetCore.Server.Tests/GrpcEndpointRouteBuilderExtensionsTests.cs +++ b/test/Grpc.AspNetCore.Server.Tests/GrpcEndpointRouteBuilderExtensionsTests.cs @@ -78,7 +78,7 @@ public void MapGrpcService_CanBind_CreatesEndpoints() var routeEndpoint1 = (RouteEndpoint)endpoints[0]; Assert.AreEqual("/Greet.Greeter/SayHello", routeEndpoint1.RoutePattern.RawText); - Assert.AreEqual("POST", ((IHttpMethodMetadata)routeEndpoint1.Metadata.Single(m => m is HttpMethodMetadata)).HttpMethods.Single()); + Assert.AreEqual("POST", routeEndpoint1.Metadata.GetMetadata().HttpMethods.Single()); var routeEndpoint2 = (RouteEndpoint)endpoints[1]; Assert.AreEqual("/Greet.Greeter/SayHellos", routeEndpoint2.RoutePattern.RawText); From 4335078c9b7adfa9420a24b0ec15cf7d44f44894 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Wed, 20 Feb 2019 11:21:08 -0800 Subject: [PATCH 03/14] Update test/Grpc.AspNetCore.Server.Tests/GrpcEndpointRouteBuilderExtensionsTests.cs Co-Authored-By: JunTaoLuo --- .../GrpcEndpointRouteBuilderExtensionsTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Grpc.AspNetCore.Server.Tests/GrpcEndpointRouteBuilderExtensionsTests.cs b/test/Grpc.AspNetCore.Server.Tests/GrpcEndpointRouteBuilderExtensionsTests.cs index 69eb3f989..6230301e5 100644 --- a/test/Grpc.AspNetCore.Server.Tests/GrpcEndpointRouteBuilderExtensionsTests.cs +++ b/test/Grpc.AspNetCore.Server.Tests/GrpcEndpointRouteBuilderExtensionsTests.cs @@ -82,7 +82,7 @@ public void MapGrpcService_CanBind_CreatesEndpoints() var routeEndpoint2 = (RouteEndpoint)endpoints[1]; Assert.AreEqual("/Greet.Greeter/SayHellos", routeEndpoint2.RoutePattern.RawText); - Assert.AreEqual("POST", ((IHttpMethodMetadata)routeEndpoint2.Metadata.Single(m => m is HttpMethodMetadata)).HttpMethods.Single()); + Assert.AreEqual("POST", routeEndpoint2.Metadata.GetMetadata().HttpMethods.Single()); } [Test] From 561b4dd53160d158a661c4a269ce7f27b133d9e4 Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 20 Feb 2019 12:53:36 -0800 Subject: [PATCH 04/14] Feedback --- .../Internal/HttpContextServerCallContext.cs | 2 +- .../Internal/PipeExtensions.cs | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/Grpc.AspNetCore.Server/Internal/HttpContextServerCallContext.cs b/src/Grpc.AspNetCore.Server/Internal/HttpContextServerCallContext.cs index 355ce9862..5aa98cdd9 100644 --- a/src/Grpc.AspNetCore.Server/Internal/HttpContextServerCallContext.cs +++ b/src/Grpc.AspNetCore.Server/Internal/HttpContextServerCallContext.cs @@ -199,7 +199,7 @@ protected override Task WriteResponseHeadersAsyncCore(Metadata responseHeaders) } } - return HttpContext.Response.StartAsync(); + return HttpContext.Response.Body.FlushAsync(); } public void Initialize() diff --git a/src/Grpc.AspNetCore.Server/Internal/PipeExtensions.cs b/src/Grpc.AspNetCore.Server/Internal/PipeExtensions.cs index 4301af37f..76bad5481 100644 --- a/src/Grpc.AspNetCore.Server/Internal/PipeExtensions.cs +++ b/src/Grpc.AspNetCore.Server/Internal/PipeExtensions.cs @@ -55,19 +55,23 @@ public static Task WriteMessageAsync(this PipeWriter pipeWriter, byte[] messageD return Task.FromException(new RpcException(SendingMessageExceedsLimitStatus)); } - if (!serverCallContext.HttpContext.Response.HasStarted) + // Must call StartAsync before the first pipeWriter.GetSpan() in WriteHeader + var response = serverCallContext.HttpContext.Response; + if (!response.HasStarted) { - return pipeWriter.WriteMessageCoreInitialAsync(messageData, serverCallContext, flush); + var startAsyncTask = response.StartAsync(); + if (!startAsyncTask.IsCompletedSuccessfully) + { + return pipeWriter.WriteMessageCoreAsyncAwaited(messageData, serverCallContext, flush, startAsyncTask); + } } return pipeWriter.WriteMessageCoreAsync(messageData, serverCallContext, flush); } - private static async Task WriteMessageCoreInitialAsync(this PipeWriter pipeWriter, byte[] messageData, HttpContextServerCallContext serverCallContext, bool flush) + private static async Task WriteMessageCoreAsyncAwaited(this PipeWriter pipeWriter, byte[] messageData, HttpContextServerCallContext serverCallContext, bool flush, Task startAsyncTask) { - // Must call StartAsync before the first pipeWriter.GetSpan() in WriteHeader - await serverCallContext.HttpContext.Response.StartAsync(); - + await startAsyncTask; await pipeWriter.WriteMessageCoreAsync(messageData, serverCallContext, flush); } From 440e8afb8ae2583f63bfc0fa5ddc37ccbddf82d8 Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 20 Feb 2019 13:55:26 -0800 Subject: [PATCH 05/14] cleanup --- src/Grpc.AspNetCore.Server/Internal/PipeExtensions.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Grpc.AspNetCore.Server/Internal/PipeExtensions.cs b/src/Grpc.AspNetCore.Server/Internal/PipeExtensions.cs index 76bad5481..9576e8cc7 100644 --- a/src/Grpc.AspNetCore.Server/Internal/PipeExtensions.cs +++ b/src/Grpc.AspNetCore.Server/Internal/PipeExtensions.cs @@ -56,14 +56,10 @@ public static Task WriteMessageAsync(this PipeWriter pipeWriter, byte[] messageD } // Must call StartAsync before the first pipeWriter.GetSpan() in WriteHeader - var response = serverCallContext.HttpContext.Response; - if (!response.HasStarted) + var startAsyncTask = serverCallContext.HttpContext.Response.StartAsync(); + if (!startAsyncTask.IsCompletedSuccessfully) { - var startAsyncTask = response.StartAsync(); - if (!startAsyncTask.IsCompletedSuccessfully) - { - return pipeWriter.WriteMessageCoreAsyncAwaited(messageData, serverCallContext, flush, startAsyncTask); - } + return pipeWriter.WriteMessageCoreAsyncAwaited(messageData, serverCallContext, flush, startAsyncTask); } return pipeWriter.WriteMessageCoreAsync(messageData, serverCallContext, flush); From aed8df0560c9a14958fbd93cc2470677512e3cf2 Mon Sep 17 00:00:00 2001 From: = Date: Wed, 20 Feb 2019 14:26:35 -0800 Subject: [PATCH 06/14] Add script to install SDK --- .travis.yml | 6 +----- build/get-dotnet.sh | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 5 deletions(-) create mode 100755 build/get-dotnet.sh diff --git a/.travis.yml b/.travis.yml index b23f6a490..0c1a61966 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,10 +8,6 @@ mono: none branches: only: - master -install: - - curl -o dotnet-sdk.tar.gz -sSL https://dotnetcli.blob.core.windows.net/dotnet/Sdk/release/3.0.1xx/dotnet-sdk-latest-linux-x64.tar.gz - - mkdir -p $PWD/dotnet - - tar zxf dotnet-sdk.tar.gz -C $PWD/dotnet - - export PATH="$PWD/dotnet:$PATH" script: + - ./build/get-dotnet.sh - ./build_and_test.sh diff --git a/build/get-dotnet.sh b/build/get-dotnet.sh new file mode 100755 index 000000000..82ea4affa --- /dev/null +++ b/build/get-dotnet.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# variables +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +OBJDIR="$DIR/obj" +global_json_path="$DIR/../global.json" +install_script_url="https://dot.net/v1/dotnet-install.sh" +install_script_path="$OBJDIR/dotnet-install.sh" + +# functions +ensure_dir() { + [ -d $1 ] || mkdir $1 +} + +# main + +sdk_version=$(jq -r .sdk.version $global_json_path) + +# download dotnet-install.sh +ensure_dir $OBJDIR + +echo "Downloading install script: $install_script_url => $install_script_path" +curl -sSL -o $install_script_path $install_script_url +chmod +x $install_script_path + +$install_script_path -v $sdk_version From 6bdce8bbe99071a31af99d846f541963402e8d8c Mon Sep 17 00:00:00 2001 From: = Date: Wed, 20 Feb 2019 14:39:46 -0800 Subject: [PATCH 07/14] Source the script to add dotnet to path --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0c1a61966..4ff6cc7e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,5 +9,5 @@ branches: only: - master script: - - ./build/get-dotnet.sh + - source build/get-dotnet.sh - ./build_and_test.sh From b930cae9691628ec9e67783a3178479e6f9e14ab Mon Sep 17 00:00:00 2001 From: = Date: Wed, 20 Feb 2019 14:49:26 -0800 Subject: [PATCH 08/14] Add dotnet to path --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4ff6cc7e2..71831a4c4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,5 +9,6 @@ branches: only: - master script: - - source build/get-dotnet.sh + - ./build/get-dotnet.sh + - export PATH="~/.dotnet/:$PATH" - ./build_and_test.sh From 82a5c0edbdeac698f0a30c38b1a9bb46b1338ace Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 20 Feb 2019 14:58:50 -0800 Subject: [PATCH 09/14] Add ps script to install SDK --- README.md | 6 +++++- build/get-dotnet.ps1 | 44 ++++++++++++++++++++++++++++++++++++++++++++ build/get-dotnet.sh | 1 + 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 build/get-dotnet.ps1 diff --git a/README.md b/README.md index 1516774be..4e4a264fc 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,11 @@ Documentation and guides are coming soon! In the mean time we suggest referring ## To develop gRPC for ASP.NET Core -Install [.NET Core SDK 3 preview 2](https://dotnet.microsoft.com/download/dotnet-core/3.0). +Installing .NET Core SDK: +``` +# Run this script before building the project. +./build/get-dotnet.sh or ./build/get-dotnet.ps1 +``` Setting up local feed with unreleased Grpc.* packages: ``` diff --git a/build/get-dotnet.ps1 b/build/get-dotnet.ps1 new file mode 100644 index 000000000..bd15ca1c5 --- /dev/null +++ b/build/get-dotnet.ps1 @@ -0,0 +1,44 @@ +#!/usr/bin/env powershell + +<# +.PARAMETER Upgrade +Upgrade the version of gRPC packages to be downloaded to the latest on https://packages.grpc.io/ +.NOTES +This function will create a file grpc-lock.txt. This lock file can be committed to source, but does not have to be. +When the lock file is not present, the script will create one using latest available version from https://packages.grpc.io/. +#> + +param ( + [switch]$Upgrade = $false +) + +Set-StrictMode -Version 2 +$ErrorActionPreference = 'Stop' + +# Variables + +$WorkingDir = $PSScriptRoot +$TempDir = Join-Path $WorkingDir 'obj' +$InstallScriptUrl = 'https://dot.net/v1/dotnet-install.ps1' +$InstallScriptPath = Join-Path $TempDir 'dotnet-install.ps1' +$GlobalJsonPath = Join-Path $WorkingDir '..' | Join-Path -ChildPath 'global.json' + +# Functions + +function Ensure-Dir([string]$path) { + if (!(Test-Path $path -PathType Container)) { + New-Item -ItemType Directory -Force -Path $path | Out-Null + } +} + +# Main + +# Resolve SDK version +$GlobalJson = Get-Content -Raw $GlobalJsonPath | ConvertFrom-Json +$SDKVersion = $GlobalJson.sdk.version + +# Download install script +Ensure-Dir $TempDir +Write-Host "Downloading install script: $InstallScriptUrl => $InstallScriptPath" +Invoke-WebRequest -Uri $InstallScriptUrl -OutFile $InstallScriptPath +&$InstallScriptPath -Version $SDKVersion \ No newline at end of file diff --git a/build/get-dotnet.sh b/build/get-dotnet.sh index 82ea4affa..4247649e8 100755 --- a/build/get-dotnet.sh +++ b/build/get-dotnet.sh @@ -16,6 +16,7 @@ ensure_dir() { # main +# resolve SDK version sdk_version=$(jq -r .sdk.version $global_json_path) # download dotnet-install.sh From 59a5504a24e79a9cee7b9695e353dcb538df7a2f Mon Sep 17 00:00:00 2001 From: = Date: Wed, 20 Feb 2019 15:25:39 -0800 Subject: [PATCH 10/14] Update --- .travis.yml | 3 ++- README.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 71831a4c4..466610796 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,8 @@ mono: none branches: only: - master -script: +install: - ./build/get-dotnet.sh - export PATH="~/.dotnet/:$PATH" +script: - ./build_and_test.sh diff --git a/README.md b/README.md index 4e4a264fc..d04d5c2f6 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Installing .NET Core SDK: Setting up local feed with unreleased Grpc.* packages: ``` -# For the time being, we are depending on unreleased Grpc.* packages. +# We may depend on unreleased Grpc.* packages. # Run this script before building the project. ./build/get-grpc.sh or ./build/get-grpc.ps1 ``` From 2838a2a938e4006ea480d578158e3cf1dae9e3ed Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 20 Feb 2019 16:24:25 -0800 Subject: [PATCH 11/14] Add a HttpResponseStartFeature --- .../Infrastructure/GrpcTestFixture.cs | 3 ++ .../TestHttpResponseStartFeature.cs | 32 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 test/FunctionalTests/Infrastructure/TestHttpResponseStartFeature.cs diff --git a/test/FunctionalTests/Infrastructure/GrpcTestFixture.cs b/test/FunctionalTests/Infrastructure/GrpcTestFixture.cs index 37b9e10d9..78782a237 100644 --- a/test/FunctionalTests/Infrastructure/GrpcTestFixture.cs +++ b/test/FunctionalTests/Infrastructure/GrpcTestFixture.cs @@ -20,6 +20,7 @@ using System.Net.Http; using FunctionalTestsWebsite.Infrastructure; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; @@ -45,6 +46,8 @@ public GrpcTestFixture() .UseStartup(); _server = new TestServer(builder); + // Temporary workaround, this should be added to the TestServer by default + _server.Features.Set(new TestHttpResponseStartFeature()); Client = _server.CreateClient(); Client.BaseAddress = new Uri("http://localhost"); diff --git a/test/FunctionalTests/Infrastructure/TestHttpResponseStartFeature.cs b/test/FunctionalTests/Infrastructure/TestHttpResponseStartFeature.cs new file mode 100644 index 000000000..36d4a3bac --- /dev/null +++ b/test/FunctionalTests/Infrastructure/TestHttpResponseStartFeature.cs @@ -0,0 +1,32 @@ +#region Copyright notice and license + +// Copyright 2019 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#endregion + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http.Features; + +namespace Grpc.AspNetCore.FunctionalTests.Infrastructure +{ + internal class TestHttpResponseStartFeature : IHttpResponseStartFeature + { + public Task StartAsync(CancellationToken token = default) + { + return Task.CompletedTask; + } + } +} From d02f434450e40ae6e838f0f703624c674dcbeee2 Mon Sep 17 00:00:00 2001 From: = Date: Wed, 20 Feb 2019 17:09:44 -0800 Subject: [PATCH 12/14] Nope that didn't work --- test/FunctionalTests/Infrastructure/GrpcTestFixture.cs | 2 -- .../Infrastructure/TestHttpResponseStartFeature.cs | 4 ++-- testassets/FunctionalTestsWebsite/Startup.cs | 2 ++ 3 files changed, 4 insertions(+), 4 deletions(-) rename {test/FunctionalTests => testassets/FunctionalTestsWebsite}/Infrastructure/TestHttpResponseStartFeature.cs (93%) diff --git a/test/FunctionalTests/Infrastructure/GrpcTestFixture.cs b/test/FunctionalTests/Infrastructure/GrpcTestFixture.cs index 78782a237..70f085686 100644 --- a/test/FunctionalTests/Infrastructure/GrpcTestFixture.cs +++ b/test/FunctionalTests/Infrastructure/GrpcTestFixture.cs @@ -46,8 +46,6 @@ public GrpcTestFixture() .UseStartup(); _server = new TestServer(builder); - // Temporary workaround, this should be added to the TestServer by default - _server.Features.Set(new TestHttpResponseStartFeature()); Client = _server.CreateClient(); Client.BaseAddress = new Uri("http://localhost"); diff --git a/test/FunctionalTests/Infrastructure/TestHttpResponseStartFeature.cs b/testassets/FunctionalTestsWebsite/Infrastructure/TestHttpResponseStartFeature.cs similarity index 93% rename from test/FunctionalTests/Infrastructure/TestHttpResponseStartFeature.cs rename to testassets/FunctionalTestsWebsite/Infrastructure/TestHttpResponseStartFeature.cs index 36d4a3bac..0139c06a5 100644 --- a/test/FunctionalTests/Infrastructure/TestHttpResponseStartFeature.cs +++ b/testassets/FunctionalTestsWebsite/Infrastructure/TestHttpResponseStartFeature.cs @@ -20,11 +20,11 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Features; -namespace Grpc.AspNetCore.FunctionalTests.Infrastructure +namespace FunctionalTestsWebsite.Infrastructure { internal class TestHttpResponseStartFeature : IHttpResponseStartFeature { - public Task StartAsync(CancellationToken token = default) + public Task StartAsync(CancellationToken token = default(CancellationToken)) { return Task.CompletedTask; } diff --git a/testassets/FunctionalTestsWebsite/Startup.cs b/testassets/FunctionalTestsWebsite/Startup.cs index 61ae6ef96..67456ef74 100644 --- a/testassets/FunctionalTestsWebsite/Startup.cs +++ b/testassets/FunctionalTestsWebsite/Startup.cs @@ -67,6 +67,8 @@ public void Configure(IApplicationBuilder app) // Workaround for https://github.com/aspnet/AspNetCore/issues/7449 context.Features.Set(new TestHttpRequestLifetimeFeature()); + // Temporary workaround, this should be added to the TestServer by default + context.Features.Set(new TestHttpResponseStartFeature()); return next(); }); From e7e4a9991bda2d1bbbc4ecc180927b8272fd1c82 Mon Sep 17 00:00:00 2001 From: = Date: Wed, 20 Feb 2019 17:12:38 -0800 Subject: [PATCH 13/14] Feedback --- src/Grpc.AspNetCore.Server/Internal/PipeExtensions.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Grpc.AspNetCore.Server/Internal/PipeExtensions.cs b/src/Grpc.AspNetCore.Server/Internal/PipeExtensions.cs index 9576e8cc7..76bad5481 100644 --- a/src/Grpc.AspNetCore.Server/Internal/PipeExtensions.cs +++ b/src/Grpc.AspNetCore.Server/Internal/PipeExtensions.cs @@ -56,10 +56,14 @@ public static Task WriteMessageAsync(this PipeWriter pipeWriter, byte[] messageD } // Must call StartAsync before the first pipeWriter.GetSpan() in WriteHeader - var startAsyncTask = serverCallContext.HttpContext.Response.StartAsync(); - if (!startAsyncTask.IsCompletedSuccessfully) + var response = serverCallContext.HttpContext.Response; + if (!response.HasStarted) { - return pipeWriter.WriteMessageCoreAsyncAwaited(messageData, serverCallContext, flush, startAsyncTask); + var startAsyncTask = response.StartAsync(); + if (!startAsyncTask.IsCompletedSuccessfully) + { + return pipeWriter.WriteMessageCoreAsyncAwaited(messageData, serverCallContext, flush, startAsyncTask); + } } return pipeWriter.WriteMessageCoreAsync(messageData, serverCallContext, flush); From d9f440fedd711e4b9ca7c6b40498c6c2cba293a0 Mon Sep 17 00:00:00 2001 From: = Date: Wed, 20 Feb 2019 17:29:40 -0800 Subject: [PATCH 14/14] Comments --- testassets/FunctionalTestsWebsite/Startup.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testassets/FunctionalTestsWebsite/Startup.cs b/testassets/FunctionalTestsWebsite/Startup.cs index 67456ef74..44c37b6a3 100644 --- a/testassets/FunctionalTestsWebsite/Startup.cs +++ b/testassets/FunctionalTestsWebsite/Startup.cs @@ -67,7 +67,7 @@ public void Configure(IApplicationBuilder app) // Workaround for https://github.com/aspnet/AspNetCore/issues/7449 context.Features.Set(new TestHttpRequestLifetimeFeature()); - // Temporary workaround, this should be added to the TestServer by default + // Workaround for https://github.com/aspnet/AspNetCore/issues/7780 context.Features.Set(new TestHttpResponseStartFeature()); return next();