Skip to content

Commit

Permalink
Target .NET Framework (#1118)
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesNK committed Feb 16, 2021
1 parent 538e372 commit 927c0e5
Show file tree
Hide file tree
Showing 59 changed files with 1,059 additions and 206 deletions.
7 changes: 7 additions & 0 deletions Grpc.DotNet.sln
Expand Up @@ -122,6 +122,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LinkerTestsClient", "testas
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LinkerTestsWebsite", "testassets\LinkerTestsWebsite\LinkerTestsWebsite.csproj", "{FC5F9350-B812-4C62-AE76-0FF437F0F362}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Net.Client.Web.Tests", "test\Grpc.Net.Client.Web.Tests\Grpc.Net.Client.Web.Tests.csproj", "{14B1CA94-1222-4D2E-B37A-1FF8676E233E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -248,6 +250,10 @@ Global
{FC5F9350-B812-4C62-AE76-0FF437F0F362}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC5F9350-B812-4C62-AE76-0FF437F0F362}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC5F9350-B812-4C62-AE76-0FF437F0F362}.Release|Any CPU.Build.0 = Release|Any CPU
{14B1CA94-1222-4D2E-B37A-1FF8676E233E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{14B1CA94-1222-4D2E-B37A-1FF8676E233E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{14B1CA94-1222-4D2E-B37A-1FF8676E233E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{14B1CA94-1222-4D2E-B37A-1FF8676E233E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -292,6 +298,7 @@ Global
{D241B525-3B50-42EA-9E43-052745549BA6} = {1B8B6117-CE39-4580-BAFA-D8026102767A}
{1FA0B07B-E65C-4380-94A4-75F10312487D} = {59C7B1F0-EE4D-4098-8596-0ADDBC305234}
{FC5F9350-B812-4C62-AE76-0FF437F0F362} = {59C7B1F0-EE4D-4098-8596-0ADDBC305234}
{14B1CA94-1222-4D2E-B37A-1FF8676E233E} = {CECC4AE8-9C4E-4727-939B-517CC2E58D65}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {CD5C2B19-49B4-480A-990C-36D98A719B07}
Expand Down
1 change: 1 addition & 0 deletions build/dependencies.props
Expand Up @@ -25,6 +25,7 @@
<SystemCommandLineRenderingPackageVersion>0.3.0-alpha.20214.1</SystemCommandLineRenderingPackageVersion>
<SystemDiagnosticsDiagnosticSourcePackageVersion>4.5.1</SystemDiagnosticsDiagnosticSourcePackageVersion>
<SystemIOPipelinesPackageVersion>4.7.2</SystemIOPipelinesPackageVersion>
<SystemNetHttpWinHttpHandlerPackageVersion>5.0.0</SystemNetHttpWinHttpHandlerPackageVersion>
<SystemSecurityPrincipalWindowsPackageVersion>4.6.0</SystemSecurityPrincipalWindowsPackageVersion>
</PropertyGroup>
</Project>
2 changes: 1 addition & 1 deletion src/Grpc.Net.Client.Web/Properties/AssemblyInfo.cs
Expand Up @@ -18,7 +18,7 @@

using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("Grpc.Net.Client.Tests,PublicKey=" +
[assembly: InternalsVisibleTo("Grpc.Net.Client.Web.Tests,PublicKey=" +
"00240000048000009400000006020000002400005253413100040000010001002f5797a92c6fcde81bd4098f43" +
"0442bb8e12768722de0b0cb1b15e955b32a11352740ee59f2c94c48edc8e177d1052536b8ac651bce11ce5da3a" +
"27fc95aff3dc604a6971417453f9483c7b5e836756d5b271bf8f2403fe186e31956148c03d804487cf642f8cc0" +
Expand Down
6 changes: 3 additions & 3 deletions src/Grpc.Net.Client/Grpc.Net.Client.csproj
Expand Up @@ -6,7 +6,7 @@

<IsGrpcPublishedPackage>true</IsGrpcPublishedPackage>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<TargetFrameworks>netstandard2.1;net5.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net5.0</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
Expand All @@ -17,8 +17,8 @@
<ItemGroup>
<Compile Include="..\Shared\CommonGrpcProtocolHelpers.cs" Link="Internal\CommonGrpcProtocolHelpers.cs" />
<Compile Include="..\Shared\DefaultDeserializationContext.cs" Link="Internal\DefaultDeserializationContext.cs" />
<Compile Include="..\Shared\HttpHandlerFactory.cs" Link="Internal\HttpHandlerFactory.cs" />
<Compile Include="..\Shared\TelemetryHeaderHandler.cs" Link="Internal\TelemetryHeaderHandler.cs" />
<Compile Include="..\Shared\HttpHandlerFactory.cs" Link="Internal\Http\HttpHandlerFactory.cs" />
<Compile Include="..\Shared\TelemetryHeaderHandler.cs" Link="Internal\Http\TelemetryHeaderHandler.cs" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 2 additions & 0 deletions src/Grpc.Net.Client/GrpcChannel.cs
Expand Up @@ -46,6 +46,7 @@ public sealed class GrpcChannel : ChannelBase, IDisposable

internal Uri Address { get; }
internal HttpMessageInvoker HttpInvoker { get; }
internal bool IsWinHttp { get; }
internal int? SendMaxMessageSize { get; }
internal int? ReceiveMaxMessageSize { get; }
internal ILoggerFactory LoggerFactory { get; }
Expand Down Expand Up @@ -76,6 +77,7 @@ internal GrpcChannel(Uri address, GrpcChannelOptions channelOptions) : base(addr

Address = address;
HttpInvoker = channelOptions.HttpClient ?? CreateInternalHttpInvoker(channelOptions.HttpHandler);
IsWinHttp = channelOptions.HttpHandler != null ? HttpHandlerFactory.HasHttpHandlerType(channelOptions.HttpHandler, "System.Net.Http.WinHttpHandler") : false;
SendMaxMessageSize = channelOptions.MaxSendMessageSize;
ReceiveMaxMessageSize = channelOptions.MaxReceiveMessageSize;
CompressionProviders = ResolveCompressionProviders(channelOptions.CompressionProviders);
Expand Down
231 changes: 231 additions & 0 deletions src/Grpc.Net.Client/Internal/ArrayBufferWriter.cs
@@ -0,0 +1,231 @@
#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.Diagnostics;

#if NETSTANDARD2_0

// Copied with permission from https://github.com/dotnet/runtime/blob/589d0dc326bf0699149f76033fa66d4b22b9a7fd/src/libraries/Common/src/System/Buffers/ArrayBufferWriter.cs
// This copy of ArrayBufferWriter is only used with .NET Stardard 2.0. Later versions of .NET ship with this type.
namespace System.Buffers
{
/// <summary>
/// Represents a heap-based, array-backed output sink into which <typeparam name="T"/> data can be written.
/// </summary>
internal sealed class ArrayBufferWriter<T> : IBufferWriter<T>
{
// Copy of Array.MaxArrayLength. For byte arrays the limit is slightly larger
private const int MaxArrayLength = 0X7FEFFFFF;

private const int DefaultInitialBufferSize = 256;

private T[] _buffer;
private int _index;


/// <summary>
/// Creates an instance of an <see cref="ArrayBufferWriter{T}"/>, in which data can be written to,
/// with the default initial capacity.
/// </summary>
public ArrayBufferWriter()
{
_buffer = Array.Empty<T>();
_index = 0;
}

/// <summary>
/// Creates an instance of an <see cref="ArrayBufferWriter{T}"/>, in which data can be written to,
/// with an initial capacity specified.
/// </summary>
/// <param name="initialCapacity">The minimum capacity with which to initialize the underlying buffer.</param>
/// <exception cref="ArgumentException">
/// Thrown when <paramref name="initialCapacity"/> is not positive (i.e. less than or equal to 0).
/// </exception>
public ArrayBufferWriter(int initialCapacity)
{
if (initialCapacity <= 0)
throw new ArgumentException(null, nameof(initialCapacity));

_buffer = new T[initialCapacity];
_index = 0;
}

/// <summary>
/// Returns the data written to the underlying buffer so far, as a <see cref="ReadOnlyMemory{T}"/>.
/// </summary>
public ReadOnlyMemory<T> WrittenMemory => _buffer.AsMemory(0, _index);

/// <summary>
/// Returns the data written to the underlying buffer so far, as a <see cref="ReadOnlySpan{T}"/>.
/// </summary>
public ReadOnlySpan<T> WrittenSpan => _buffer.AsSpan(0, _index);

/// <summary>
/// Returns the amount of data written to the underlying buffer so far.
/// </summary>
public int WrittenCount => _index;

/// <summary>
/// Returns the total amount of space within the underlying buffer.
/// </summary>
public int Capacity => _buffer.Length;

/// <summary>
/// Returns the amount of space available that can still be written into without forcing the underlying buffer to grow.
/// </summary>
public int FreeCapacity => _buffer.Length - _index;

/// <summary>
/// Clears the data written to the underlying buffer.
/// </summary>
/// <remarks>
/// You must clear the <see cref="ArrayBufferWriter{T}"/> before trying to re-use it.
/// </remarks>
public void Clear()
{
Debug.Assert(_buffer.Length >= _index);
_buffer.AsSpan(0, _index).Clear();
_index = 0;
}

/// <summary>
/// Notifies <see cref="IBufferWriter{T}"/> that <paramref name="count"/> amount of data was written to the output <see cref="Span{T}"/>/<see cref="Memory{T}"/>
/// </summary>
/// <exception cref="ArgumentException">
/// Thrown when <paramref name="count"/> is negative.
/// </exception>
/// <exception cref="InvalidOperationException">
/// Thrown when attempting to advance past the end of the underlying buffer.
/// </exception>
/// <remarks>
/// You must request a new buffer after calling Advance to continue writing more data and cannot write to a previously acquired buffer.
/// </remarks>
public void Advance(int count)
{
if (count < 0)
throw new ArgumentException(null, nameof(count));

if (_index > _buffer.Length - count)
ThrowInvalidOperationException_AdvancedTooFar(_buffer.Length);

_index += count;
}

/// <summary>
/// Returns a <see cref="Memory{T}"/> to write to that is at least the requested length (specified by <paramref name="sizeHint"/>).
/// If no <paramref name="sizeHint"/> is provided (or it's equal to <code>0</code>), some non-empty buffer is returned.
/// </summary>
/// <exception cref="ArgumentException">
/// Thrown when <paramref name="sizeHint"/> is negative.
/// </exception>
/// <remarks>
/// This will never return an empty <see cref="Memory{T}"/>.
/// </remarks>
/// <remarks>
/// There is no guarantee that successive calls will return the same buffer or the same-sized buffer.
/// </remarks>
/// <remarks>
/// You must request a new buffer after calling Advance to continue writing more data and cannot write to a previously acquired buffer.
/// </remarks>
public Memory<T> GetMemory(int sizeHint = 0)
{
CheckAndResizeBuffer(sizeHint);
Debug.Assert(_buffer.Length > _index);
return _buffer.AsMemory(_index);
}

/// <summary>
/// Returns a <see cref="Span{T}"/> to write to that is at least the requested length (specified by <paramref name="sizeHint"/>).
/// If no <paramref name="sizeHint"/> is provided (or it's equal to <code>0</code>), some non-empty buffer is returned.
/// </summary>
/// <exception cref="ArgumentException">
/// Thrown when <paramref name="sizeHint"/> is negative.
/// </exception>
/// <remarks>
/// This will never return an empty <see cref="Span{T}"/>.
/// </remarks>
/// <remarks>
/// There is no guarantee that successive calls will return the same buffer or the same-sized buffer.
/// </remarks>
/// <remarks>
/// You must request a new buffer after calling Advance to continue writing more data and cannot write to a previously acquired buffer.
/// </remarks>
public Span<T> GetSpan(int sizeHint = 0)
{
CheckAndResizeBuffer(sizeHint);
Debug.Assert(_buffer.Length > _index);
return _buffer.AsSpan(_index);
}

private void CheckAndResizeBuffer(int sizeHint)
{
if (sizeHint < 0)
throw new ArgumentException(nameof(sizeHint));

if (sizeHint == 0)
{
sizeHint = 1;
}

if (sizeHint > FreeCapacity)
{
int currentLength = _buffer.Length;

// Attempt to grow by the larger of the sizeHint and double the current size.
int growBy = Math.Max(sizeHint, currentLength);

if (currentLength == 0)
{
growBy = Math.Max(growBy, DefaultInitialBufferSize);
}

int newSize = currentLength + growBy;

if ((uint)newSize > int.MaxValue)
{
// Attempt to grow to MaxArrayLength.
uint needed = (uint)(currentLength - FreeCapacity + sizeHint);
Debug.Assert(needed > currentLength);

if (needed > MaxArrayLength)
{
ThrowOutOfMemoryException(needed);
}

newSize = MaxArrayLength;
}

Array.Resize(ref _buffer, newSize);
}

Debug.Assert(FreeCapacity > 0 && FreeCapacity >= sizeHint);
}

private static void ThrowInvalidOperationException_AdvancedTooFar(int capacity)
{
throw new InvalidOperationException($"Cannot advance past the end of the buffer, which has a size of {capacity}.");
}

private static void ThrowOutOfMemoryException(uint capacity)
{
throw new OutOfMemoryException($"Cannot allocate a buffer of size {capacity}.");
}
}
}

#endif
64 changes: 64 additions & 0 deletions src/Grpc.Net.Client/Internal/CompatibilityExtensions.cs
@@ -0,0 +1,64 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace Grpc.Net.Client.Internal
{
internal static class CompatibilityExtensions
{
#if !NETSTANDARD2_0
public static readonly Version Version20 = HttpVersion.Version20;
#else
public static readonly Version Version20 = new Version(2, 0);
public static readonly string ResponseTrailersKey = "__ResponseTrailers";
#endif

public static HttpHeaders GetTrailingHeaders(this HttpResponseMessage responseMessage)
{
#if !NETSTANDARD2_0
return responseMessage.TrailingHeaders;
#else
if (!responseMessage.RequestMessage.Properties.TryGetValue(ResponseTrailersKey, out var headers))
{
throw new InvalidOperationException();
}
return (HttpHeaders)headers;
#endif
}

[Conditional("DEBUG")]
public static void Assert([DoesNotReturnIf(false)] bool condition, string? message = null)
{
Debug.Assert(condition, message);
}

public static bool IsCompletedSuccessfully(this Task task)
{
// IsCompletedSuccessfully is the faster method, but only currently exposed on .NET Core 2.0+
#if !NETSTANDARD2_0
return task.IsCompletedSuccessfully;
#else
return task.Status == TaskStatus.RanToCompletion;
#endif
}

#if !NETSTANDARD2_0
public static bool IsCompletedSuccessfully(this ValueTask task)
{
return task.IsCompletedSuccessfully;
}

public static bool IsCompletedSuccessfully<T>(this ValueTask<T> task)
{
return task.IsCompletedSuccessfully;
}
#endif
}
}
4 changes: 2 additions & 2 deletions src/Grpc.Net.Client/Internal/GrpcCall.NonGeneric.cs
Expand Up @@ -83,8 +83,8 @@ protected bool TryGetTrailers([NotNullWhen(true)] out Metadata? trailers)
return false;
}

Debug.Assert(HttpResponse != null);
Trailers = GrpcProtocolHelpers.BuildMetadata(HttpResponse.TrailingHeaders);
CompatibilityExtensions.Assert(HttpResponse != null);
Trailers = GrpcProtocolHelpers.BuildMetadata(HttpResponse.GetTrailingHeaders());
}

trailers = Trailers;
Expand Down

0 comments on commit 927c0e5

Please sign in to comment.