Compare commits

..

3 Commits

Author SHA1 Message Date
Jan Tattermusch 6bc7e0a87d
Bump version to v2.28.0-pre2 (#816) 2020-03-11 10:39:12 +01:00
James Newton-King 06fa6c2fc7
Fix GrpcWebHandler not always resetting HTTP version back to 2.0 (#810) 2020-03-09 14:10:26 -07:00
Jan Tattermusch 0b37fb33cc
Update version to 2.28.0-pre1 (#799) 2020-03-02 18:23:47 -08:00
1237 changed files with 39052 additions and 124094 deletions

View File

@ -1,3 +0,0 @@
**/bin
**/obj
.vs

View File

@ -1,406 +0,0 @@
; EditorConfig to support per-solution formatting.
; Use the EditorConfig VS add-in to make this work.
; http://editorconfig.org/
;
; Here are some resources for what's supported for .NET/C#
; https://kent-boogaart.com/blog/editorconfig-reference-for-c-developers
; https://learn.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference
;
; Be **careful** editing this because some of the rules don't support adding a severity level
; For instance if you change to `dotnet_sort_system_directives_first = true:warning` (adding `:warning`)
; then the rule will be silently ignored.
; This is the default for the codeline.
root = true
[*]
indent_style = space
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.cs]
indent_size = 4
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
# Disallow throw expressions.
csharp_style_throw_expression = false: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
# Namespace settings
csharp_style_namespace_declarations = file_scoped
# Brace settings
csharp_prefer_braces = true # Prefer curly braces even for one line of code
[*.{xml,config,*proj,nuspec,props,resx,targets,yml,tasks}]
indent_size = 2
# Xml config files
[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
indent_size = 2
[*.json]
indent_size = 2
[*.{ps1,psm1}]
indent_size = 4
[*.sh]
indent_size = 4
end_of_line = lf
[*.{razor,cshtml}]
charset = utf-8-bom
[*.{cs,vb}]
# SYSLIB1054: Use 'LibraryImportAttribute' instead of 'DllImportAttribute' to generate P/Invoke marshalling code at compile time
dotnet_diagnostic.SYSLIB1054.severity = warning
# CA1018: Mark attributes with AttributeUsageAttribute
dotnet_diagnostic.CA1018.severity = warning
# CA1047: Do not declare protected member in sealed type
dotnet_diagnostic.CA1047.severity = warning
# CA1305: Specify IFormatProvider
dotnet_diagnostic.CA1305.severity = warning
# CA1507: Use nameof to express symbol names
dotnet_diagnostic.CA1507.severity = warning
# CA1510: Use ArgumentNullException throw helper
dotnet_diagnostic.CA1510.severity = warning
# CA1511: Use ArgumentException throw helper
dotnet_diagnostic.CA1511.severity = warning
# CA1512: Use ArgumentOutOfRangeException throw helper
dotnet_diagnostic.CA1512.severity = warning
# CA1513: Use ObjectDisposedException throw helper
dotnet_diagnostic.CA1513.severity = warning
# CA1725: Parameter names should match base declaration
dotnet_diagnostic.CA1725.severity = suggestion
# CA1802: Use literals where appropriate
dotnet_diagnostic.CA1802.severity = warning
# CA1805: Do not initialize unnecessarily
dotnet_diagnostic.CA1805.severity = warning
# CA1810: Do not initialize unnecessarily
dotnet_diagnostic.CA1810.severity = warning
# CA1821: Remove empty Finalizers
dotnet_diagnostic.CA1821.severity = warning
# CA1822: Make member static
dotnet_diagnostic.CA1822.severity = warning
dotnet_code_quality.CA1822.api_surface = private, internal
# CA1823: Avoid unused private fields
dotnet_diagnostic.CA1823.severity = warning
# CA1825: Avoid zero-length array allocations
dotnet_diagnostic.CA1825.severity = warning
# CA1826: Do not use Enumerable methods on indexable collections. Instead use the collection directly
dotnet_diagnostic.CA1826.severity = warning
# CA1827: Do not use Count() or LongCount() when Any() can be used
dotnet_diagnostic.CA1827.severity = warning
# CA1828: Do not use CountAsync() or LongCountAsync() when AnyAsync() can be used
dotnet_diagnostic.CA1828.severity = warning
# CA1829: Use Length/Count property instead of Count() when available
dotnet_diagnostic.CA1829.severity = warning
# CA1830: Prefer strongly-typed Append and Insert method overloads on StringBuilder
dotnet_diagnostic.CA1830.severity = warning
# CA1831: Use AsSpan or AsMemory instead of Range-based indexers when appropriate
# CA1832: Use AsSpan or AsMemory instead of Range-based indexers when appropriate
# CA1833: Use AsSpan or AsMemory instead of Range-based indexers when appropriate
dotnet_diagnostic.CA1831.severity = warning
dotnet_diagnostic.CA1832.severity = warning
dotnet_diagnostic.CA1833.severity = warning
# CA1834: Consider using 'StringBuilder.Append(char)' when applicable
dotnet_diagnostic.CA1834.severity = warning
# CA1835: Prefer the 'Memory'-based overloads for 'ReadAsync' and 'WriteAsync'
dotnet_diagnostic.CA1835.severity = warning
# CA1836: Prefer IsEmpty over Count
dotnet_diagnostic.CA1836.severity = warning
# CA1837: Use 'Environment.ProcessId'
dotnet_diagnostic.CA1837.severity = warning
# CA1838: Avoid 'StringBuilder' parameters for P/Invokes
dotnet_diagnostic.CA1838.severity = warning
# CA1839: Use 'Environment.ProcessPath'
dotnet_diagnostic.CA1839.severity = warning
# CA1840: Use 'Environment.CurrentManagedThreadId'
dotnet_diagnostic.CA1840.severity = warning
# CA1841: Prefer Dictionary.Contains methods
dotnet_diagnostic.CA1841.severity = warning
# CA1842: Do not use 'WhenAll' with a single task
dotnet_diagnostic.CA1842.severity = warning
# CA1843: Do not use 'WaitAll' with a single task
dotnet_diagnostic.CA1843.severity = warning
# CA1844: Provide memory-based overrides of async methods when subclassing 'Stream'
dotnet_diagnostic.CA1844.severity = warning
# CA1845: Use span-based 'string.Concat'
dotnet_diagnostic.CA1845.severity = warning
# CA1846: Prefer AsSpan over Substring
dotnet_diagnostic.CA1846.severity = warning
# CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters
dotnet_diagnostic.CA1847.severity = warning
# CA1852: Seal internal types
dotnet_diagnostic.CA1852.severity = warning
# CA1854: Prefer the IDictionary.TryGetValue(TKey, out TValue) method
dotnet_diagnostic.CA1854.severity = warning
# CA1855: Prefer 'Clear' over 'Fill'
dotnet_diagnostic.CA1855.severity = warning
# CA1856: Incorrect usage of ConstantExpected attribute
dotnet_diagnostic.CA1856.severity = error
# CA1857: A constant is expected for the parameter
dotnet_diagnostic.CA1857.severity = warning
# CA1858: Use 'StartsWith' instead of 'IndexOf'
dotnet_diagnostic.CA1858.severity = warning
# CA2007: Consider calling ConfigureAwait on the awaited task
dotnet_diagnostic.CA2007.severity = warning
# CA2008: Do not create tasks without passing a TaskScheduler
dotnet_diagnostic.CA2008.severity = warning
# CA2009: Do not call ToImmutableCollection on an ImmutableCollection value
dotnet_diagnostic.CA2009.severity = warning
# CA2011: Avoid infinite recursion
dotnet_diagnostic.CA2011.severity = warning
# CA2012: Use ValueTask correctly
dotnet_diagnostic.CA2012.severity = warning
# CA2013: Do not use ReferenceEquals with value types
dotnet_diagnostic.CA2013.severity = warning
# CA2014: Do not use stackalloc in loops.
dotnet_diagnostic.CA2014.severity = warning
# CA2016: Forward the 'CancellationToken' parameter to methods that take one
dotnet_diagnostic.CA2016.severity = warning
# CA2200: Rethrow to preserve stack details
dotnet_diagnostic.CA2200.severity = warning
# CA2208: Instantiate argument exceptions correctly
dotnet_diagnostic.CA2208.severity = warning
# CA2245: Do not assign a property to itself
dotnet_diagnostic.CA2245.severity = warning
# CA2246: Assigning symbol and its member in the same statement
dotnet_diagnostic.CA2246.severity = warning
# CA2249: Use string.Contains instead of string.IndexOf to improve readability.
dotnet_diagnostic.CA2249.severity = warning
# IDE0005: Remove unnecessary usings
dotnet_diagnostic.IDE0005.severity = warning
# IDE0011: Curly braces to surround blocks of code
dotnet_diagnostic.IDE0011.severity = warning
# IDE0020: Use pattern matching to avoid is check followed by a cast (with variable)
dotnet_diagnostic.IDE0020.severity = warning
# IDE0029: Use coalesce expression (non-nullable types)
dotnet_diagnostic.IDE0029.severity = warning
# IDE0030: Use coalesce expression (nullable types)
dotnet_diagnostic.IDE0030.severity = warning
# IDE0031: Use null propagation
dotnet_diagnostic.IDE0031.severity = warning
# IDE0035: Remove unreachable code
dotnet_diagnostic.IDE0035.severity = warning
# IDE0036: Order modifiers
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
dotnet_diagnostic.IDE0036.severity = warning
# IDE0038: Use pattern matching to avoid is check followed by a cast (without variable)
dotnet_diagnostic.IDE0038.severity = warning
# IDE0043: Format string contains invalid placeholder
dotnet_diagnostic.IDE0043.severity = warning
# IDE0044: Make field readonly
dotnet_diagnostic.IDE0044.severity = warning
# IDE0051: Remove unused private members
dotnet_diagnostic.IDE0051.severity = warning
# IDE0055: All formatting rules
dotnet_diagnostic.IDE0055.severity = suggestion
# IDE0059: Unnecessary assignment to a value
dotnet_diagnostic.IDE0059.severity = warning
# IDE0060: Remove unused parameter
dotnet_code_quality_unused_parameters = non_public
dotnet_diagnostic.IDE0060.severity = warning
# IDE0062: Make local function static
dotnet_diagnostic.IDE0062.severity = warning
# IDE0161: Convert to file-scoped namespace
dotnet_diagnostic.IDE0161.severity = warning
# IDE0200: Lambda expression can be removed
dotnet_diagnostic.IDE0200.severity = warning
# IDE2000: Disallow multiple blank lines
dotnet_style_allow_multiple_blank_lines_experimental = false
dotnet_diagnostic.IDE2000.severity = warning
[{test,tests,testassets,examples,perf,scripts,stress}/**.cs]
# CA1018: Mark attributes with AttributeUsageAttribute
dotnet_diagnostic.CA1018.severity = suggestion
# CA1507: Use nameof to express symbol names
dotnet_diagnostic.CA1507.severity = suggestion
# CA1510: Use ArgumentNullException throw helper
dotnet_diagnostic.CA1510.severity = suggestion
# CA1511: Use ArgumentException throw helper
dotnet_diagnostic.CA1511.severity = suggestion
# CA1512: Use ArgumentOutOfRangeException throw helper
dotnet_diagnostic.CA1512.severity = suggestion
# CA1513: Use ObjectDisposedException throw helper
dotnet_diagnostic.CA1513.severity = suggestion
# CA1802: Use literals where appropriate
dotnet_diagnostic.CA1802.severity = suggestion
# CA1805: Do not initialize unnecessarily
dotnet_diagnostic.CA1805.severity = suggestion
# CA1810: Do not initialize unnecessarily
dotnet_diagnostic.CA1810.severity = suggestion
# CA1822: Make member static
dotnet_diagnostic.CA1822.severity = suggestion
# CA1823: Avoid zero-length array allocations
dotnet_diagnostic.CA1825.severity = suggestion
# CA1826: Do not use Enumerable methods on indexable collections. Instead use the collection directly
dotnet_diagnostic.CA1826.severity = suggestion
# CA1827: Do not use Count() or LongCount() when Any() can be used
dotnet_diagnostic.CA1827.severity = suggestion
# CA1829: Use Length/Count property instead of Count() when available
dotnet_diagnostic.CA1829.severity = suggestion
# CA1834: Consider using 'StringBuilder.Append(char)' when applicable
dotnet_diagnostic.CA1834.severity = suggestion
# CA1835: Prefer the 'Memory'-based overloads for 'ReadAsync' and 'WriteAsync'
dotnet_diagnostic.CA1835.severity = suggestion
# CA1837: Use 'Environment.ProcessId'
dotnet_diagnostic.CA1837.severity = suggestion
# CA1838: Avoid 'StringBuilder' parameters for P/Invokes
dotnet_diagnostic.CA1838.severity = suggestion
# CA1841: Prefer Dictionary.Contains methods
dotnet_diagnostic.CA1841.severity = suggestion
# CA1844: Provide memory-based overrides of async methods when subclassing 'Stream'
dotnet_diagnostic.CA1844.severity = suggestion
# CA1845: Use span-based 'string.Concat'
dotnet_diagnostic.CA1845.severity = suggestion
# CA1846: Prefer AsSpan over Substring
dotnet_diagnostic.CA1846.severity = suggestion
# CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters
dotnet_diagnostic.CA1847.severity = suggestion
# CA1852: Seal internal types
dotnet_diagnostic.CA1852.severity = suggestion
# CA1854: Prefer the IDictionary.TryGetValue(TKey, out TValue) method
dotnet_diagnostic.CA1854.severity = suggestion
# CA1855: Prefer 'Clear' over 'Fill'
dotnet_diagnostic.CA1855.severity = suggestion
# CA1856: Incorrect usage of ConstantExpected attribute
dotnet_diagnostic.CA1856.severity = suggestion
# CA1857: A constant is expected for the parameter
dotnet_diagnostic.CA1857.severity = suggestion
# CA1858: Use 'StartsWith' instead of 'IndexOf'
dotnet_diagnostic.CA1858.severity = suggestion
# CA2007: Consider calling ConfigureAwait on the awaited task
dotnet_diagnostic.CA2007.severity = suggestion
# CA2008: Do not create tasks without passing a TaskScheduler
dotnet_diagnostic.CA2008.severity = suggestion
# CA2012: Use ValueTask correctly
dotnet_diagnostic.CA2012.severity = suggestion
# CA2249: Use string.Contains instead of string.IndexOf to improve readability.
dotnet_diagnostic.CA2249.severity = suggestion
# IDE0005: Remove unnecessary usings
dotnet_diagnostic.IDE0005.severity = suggestion
# IDE0020: Use pattern matching to avoid is check followed by a cast (with variable)
dotnet_diagnostic.IDE0020.severity = suggestion
# IDE0029: Use coalesce expression (non-nullable types)
dotnet_diagnostic.IDE0029.severity = suggestion
# IDE0030: Use coalesce expression (nullable types)
dotnet_diagnostic.IDE0030.severity = suggestion
# IDE0031: Use null propagation
dotnet_diagnostic.IDE0031.severity = suggestion
# IDE0038: Use pattern matching to avoid is check followed by a cast (without variable)
dotnet_diagnostic.IDE0038.severity = suggestion
# IDE0044: Make field readonly
dotnet_diagnostic.IDE0044.severity = suggestion
# IDE0051: Remove unused private members
dotnet_diagnostic.IDE0051.severity = suggestion
# IDE0059: Unnecessary assignment to a value
dotnet_diagnostic.IDE0059.severity = suggestion
# IDE0060: Remove unused parameters
dotnet_diagnostic.IDE0060.severity = suggestion
# IDE0062: Make local function static
dotnet_diagnostic.IDE0062.severity = suggestion
# IDE0200: Lambda expression can be removed
dotnet_diagnostic.IDE0200.severity = suggestion
# CA2016: Forward the 'CancellationToken' parameter to methods that take one
dotnet_diagnostic.CA2016.severity = suggestion

View File

@ -1,5 +0,0 @@
blank_issues_enabled: true
contact_links:
- name: Issue with Grpc.Core
url: https://github.com/grpc/grpc/issues/new/choose
about: Please open issues relating to Grpc.Core in grpc/grpc.

View File

@ -1,46 +0,0 @@
name: Build and Test
on:
push:
branches: [ master ]
pull_request:
branches: [ '**' ]
schedule:
- cron: 0 0 * * * # daily at 00:00
env:
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
jobs:
build:
name: Basic Tests
runs-on: ubuntu-22.04
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Install dotnet
run: ./build/get-dotnet.sh
- name: Build and run tests
run: ./build_and_test.sh
- uses: actions/upload-artifact@v4
if: always()
with:
name: artifacts
path: artifacts
if-no-files-found: error
grpc_web:
name: gRPC-Web Tests
runs-on: ubuntu-22.04
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Run interop tests
run: ./grpcweb_interoptests.sh

1
.gitignore vendored
View File

@ -34,6 +34,7 @@ launchSettings.json
BenchmarkDotNet.Artifacts/
BDN.Generated/
binaries/
global.json
.vscode/
*.binlog
build/feed

14
.travis.yml Normal file
View File

@ -0,0 +1,14 @@
language: csharp
sudo: required
dist: xenial
env:
global:
- DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
mono: none
branches:
only:
- master
install:
- ./build/get-dotnet.sh
script:
- ./build_and_test.sh

View File

@ -1,4 +1,6 @@
<Project>
<Import Project="build\sources.props" />
<Import Project="build\dependencies.props" />
<Import Project="build\version.props" />
<PropertyGroup>
@ -10,23 +12,12 @@
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)keys\Grpc.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
<!-- Don't make missing XML docs a fatal build error, but still surface so we have visibility into undocumented APIs. -->
<WarningsNotAsErrors>$(WarningsNotAsErrors);CS1591</WarningsNotAsErrors>
<!-- Disable warnings about AOT and trimming features on older targets, e.g. netstandard2.0.
For now, continue to apply these features to these targets because some packages don't have a target that supports them -->
<NoWarn>$(NoWarn);NETSDK1195;NETSDK1210</NoWarn>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<LangVersion>12.0</LangVersion>
<LangVersion>8.0</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<!-- Some packages generate warnings when used on TFMs that are out of support (or almost out of support) -->
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
</PropertyGroup>
</Project>

View File

@ -17,38 +17,14 @@
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<CodeAnalysisRuleset>$(MSBuildThisFileDirectory)Grpc.DotNet.ruleset</CodeAnalysisRuleset>
<IsTrimmable>true</IsTrimmable>
<EnableAOTAnalyzer>true</EnableAOTAnalyzer>
</PropertyGroup>
<!-- IsGrpcPublishedPackage is set in csproj so related config must be in targets file -->
<ItemGroup Condition="'$(IsGrpcPublishedPackage)' == 'true'">
<None Include="$(PackageIconFullPath)" Pack="true" PackagePath="\"/>
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" PrivateAssets="All" />
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="$(MicrosoftCodeAnalysisFxCopAnalyzersPackageVersion)" PrivateAssets="All" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="$(MicrosoftSourceLinkGitHubPackageVersion)" PrivateAssets="All" />
</ItemGroup>
<ItemGroup Condition="$(MSBuildProjectName.EndsWith('Tests'))">
<Using Include="NUnit.Framework.Legacy.ClassicAssert" Alias="Assert" />
<Using Include="NUnit.Framework.Legacy" />
<Using Include="NUnit.Framework" />
</ItemGroup>
<!--
Make a netstandard2.1 copy of the .net ILLinkPack to work around a trimming issue.
See https://github.com/dotnet/linker/issues/3175
TODO: Remove once .NET 8 + trimming + netstandard2.1 is fixed.
-->
<Target Name="_FixKnownILLinkPack"
BeforeTargets="ProcessFrameworkReferences">
<ItemGroup>
<KnownILLinkPack Include="@(KnownILLinkPack)"
Condition="'%(TargetFramework)' == 'net8.0'"
TargetFramework="netstandard2.1"
ILLinkPackVersion="%(KnownILLinkPack.ILLinkPackVersion)" />
</ItemGroup>
</Target>
</Project>

View File

@ -1,88 +0,0 @@
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<MicrosoftAspNetCoreAppPackageVersion>10.0.0-preview.6.25358.103</MicrosoftAspNetCoreAppPackageVersion>
<MicrosoftAspNetCoreApp9PackageVersion>9.0.4</MicrosoftAspNetCoreApp9PackageVersion>
<MicrosoftAspNetCoreApp8PackageVersion>8.0.15</MicrosoftAspNetCoreApp8PackageVersion>
<GrpcDotNetPackageVersion>2.70.0</GrpcDotNetPackageVersion>
<OpenTelemetryPackageVersion>1.6.0</OpenTelemetryPackageVersion>
<OpenTelemetryIntergationPackageVersion>1.8.1</OpenTelemetryIntergationPackageVersion>
<OpenTelemetryGrpcPackageVersion>1.8.0-beta.1</OpenTelemetryGrpcPackageVersion>
<MicrosoftExtensionsPackageVersion>10.0.0-preview.6.25358.103</MicrosoftExtensionsPackageVersion>
<MicrosoftExtensionsLtsPackageVersion>8.0.0</MicrosoftExtensionsLtsPackageVersion>
</PropertyGroup>
<ItemGroup>
<!-- ASP.NET Core -->
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly" Version="$(MicrosoftAspNetCoreAppPackageVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="$(MicrosoftAspNetCoreAppPackageVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="$(MicrosoftAspNetCoreAppPackageVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.Certificate" Version="$(MicrosoftAspNetCoreAppPackageVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="$(MicrosoftAspNetCoreAppPackageVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="$(MicrosoftAspNetCoreAppPackageVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="$(MicrosoftAspNetCoreAppPackageVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.Grpc.JsonTranscoding" Version="$(MicrosoftAspNetCoreAppPackageVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.Grpc.Swagger" Version="0.8.0" />
<!-- Extensions -->
<PackageVersion Include="Microsoft.Extensions.Http" Version="$(MicrosoftExtensionsPackageVersion)" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="$(MicrosoftExtensionsPackageVersion)" />
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsPackageVersion)" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="$(MicrosoftExtensionsPackageVersion)" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="$(MicrosoftExtensionsPackageVersion)" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="$(MicrosoftExtensionsPackageVersion)" />
<!-- gRPC -->
<PackageVersion Include="Grpc.Tools" Version="2.71.0" />
<PackageVersion Include="Grpc.Core" Version="2.46.6" />
<PackageVersion Include="Grpc.Core.Api" Version="$(GrpcDotNetPackageVersion)"/>
<PackageVersion Include="Grpc.Net.Client" Version="$(GrpcDotNetPackageVersion)" />
<PackageVersion Include="Grpc.Net.Client.Web" Version="$(GrpcDotNetPackageVersion)" />
<PackageVersion Include="Grpc.Net.ClientFactory" Version="$(GrpcDotNetPackageVersion)" />
<PackageVersion Include="Grpc.AspNetCore" Version="$(GrpcDotNetPackageVersion)" />
<PackageVersion Include="Grpc.AspNetCore.Server" Version="$(GrpcDotNetPackageVersion)" />
<PackageVersion Include="Grpc.AspNetCore.Web" Version="$(GrpcDotNetPackageVersion)" />
<PackageVersion Include="Grpc.Reflection" Version="$(GrpcDotNetPackageVersion)" />
<PackageVersion Include="Grpc.AspNetCore.Server.Reflection" Version="$(GrpcDotNetPackageVersion)" />
<PackageVersion Include="Grpc.HealthCheck" Version="$(GrpcDotNetPackageVersion)" />
<PackageVersion Include="Grpc.AspNetCore.HealthChecks" Version="$(GrpcDotNetPackageVersion)" />
<PackageVersion Include="Grpc.Auth" Version="$(GrpcDotNetPackageVersion)" />
<PackageVersion Include="Grpc.StatusProto" Version="$(GrpcDotNetPackageVersion)" />
<!-- OpenTelemetry -->
<PackageVersion Include="OpenTelemetry" Version="$(OpenTelemetryPackageVersion)" />
<PackageVersion Include="OpenTelemetry.Exporter.Zipkin" Version="$(OpenTelemetryPackageVersion)" />
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="$(OpenTelemetryPackageVersion)" />
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="$(OpenTelemetryIntergationPackageVersion)" />
<PackageVersion Include="OpenTelemetry.Instrumentation.GrpcNetClient" Version="$(OpenTelemetryGrpcPackageVersion)" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="$(OpenTelemetryIntergationPackageVersion)" />
<!-- Other -->
<PackageVersion Include="BenchmarkDotNet" Version="0.15.2" />
<PackageVersion Include="CommandLineParser" Version="2.5.0" />
<PackageVersion Include="Google.Api.CommonProtos" Version="2.16.0" />
<PackageVersion Include="Google.Apis.Auth" Version="1.70.0" />
<PackageVersion Include="Google.Protobuf" Version="3.31.1" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
<PackageVersion Include="Microsoft.Build.Locator" Version="1.5.5" />
<PackageVersion Include="Microsoft.Build" Version="17.3.2" />
<PackageVersion Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="10.0.0-preview.25358.103" />
<PackageVersion Include="Microsoft.Crank.EventSources" Version="0.2.0-alpha.25128.2" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<PackageVersion Include="Microsoft.Win32.Registry" Version="4.6.0" />
<PackageVersion Include="Moq" Version="4.20.70" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Nunit" Version="4.3.2" />
<PackageVersion Include="NUnit3TestAdapter" Version="5.0.0" />
<PackageVersion Include="protobuf-net.Grpc.AspNetCore" Version="1.0.140" />
<PackageVersion Include="protobuf-net.Grpc" Version="1.0.140" />
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
<PackageVersion Include="System.CommandLine.Rendering" Version="0.4.0-alpha.22272.1" />
<PackageVersion Include="System.Diagnostics.DiagnosticSource" Version="6.0.1" />
<PackageVersion Include="System.Memory" Version="4.5.3" />
<PackageVersion Include="System.Net.Http.WinHttpHandler" Version="8.0.3" />
<PackageVersion Include="System.Security.Principal.Windows" Version="5.0.0" />
<PackageVersion Include="System.Text.Json" Version="8.0.6" />
<PackageVersion Include="System.Threading.Channels" Version="4.6.0" />
</ItemGroup>
</Project>

271
Grpc.DotNet.sln Normal file
View File

@ -0,0 +1,271 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28527.54
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8C62055F-8CD7-4859-9001-634D544DF2AE}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{CECC4AE8-9C4E-4727-939B-517CC2E58D65}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.AspNetCore.Server", "src\Grpc.AspNetCore.Server\Grpc.AspNetCore.Server.csproj", "{89ED416F-92F1-4425-9379-D4E76A285860}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.AspNetCore.Server.Tests", "test\Grpc.AspNetCore.Server.Tests\Grpc.AspNetCore.Server.Tests.csproj", "{278B1311-41BF-4345-947E-7B70E277FC3C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.AspNetCore.FunctionalTests", "test\FunctionalTests\Grpc.AspNetCore.FunctionalTests.csproj", "{B190F61D-854C-4EE1-9532-B81AB3215F90}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "perf", "perf", "{4163E1B3-4D75-46B4-9107-9A158FD708FC}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "testassets", "testassets", "{59C7B1F0-EE4D-4098-8596-0ADDBC305234}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Proto", "Proto", "{BF1393D4-6099-4EF9-85BB-7EE6CBEB920C}"
ProjectSection(SolutionItems) = preProject
testassets\Proto\any.proto = testassets\Proto\any.proto
testassets\Proto\authorize.proto = testassets\Proto\authorize.proto
testassets\Proto\chat.proto = testassets\Proto\chat.proto
testassets\Proto\compression.proto = testassets\Proto\compression.proto
testassets\Proto\count.proto = testassets\Proto\count.proto
testassets\Proto\greet.proto = testassets\Proto\greet.proto
testassets\Proto\lifetime.proto = testassets\Proto\lifetime.proto
testassets\Proto\nested.proto = testassets\Proto\nested.proto
examples\Proto\race.proto = examples\Proto\race.proto
testassets\Proto\singleton.proto = testassets\Proto\singleton.proto
testassets\Proto\streaming.proto = testassets\Proto\streaming.proto
testassets\Proto\unimplemented.proto = testassets\Proto\unimplemented.proto
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FunctionalTestsWebsite", "testassets\FunctionalTestsWebsite\FunctionalTestsWebsite.csproj", "{7B95289B-4992-4C0D-B26F-8EC58F81FC96}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarkapps", "benchmarkapps", "{1B8B6117-CE39-4580-BAFA-D8026102767A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BenchmarkClient", "perf\benchmarkapps\BenchmarkClient\BenchmarkClient.csproj", "{B10D4986-25D2-4414-B500-627D89505914}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{310E5783-455A-4D09-A7AE-39DC2AB09504}"
ProjectSection(SolutionItems) = preProject
perf\benchmarkapps\Shared\benchmark_service.proto = perf\benchmarkapps\Shared\benchmark_service.proto
perf\benchmarkapps\Shared\BenchmarkConfigurationHelpers.cs = perf\benchmarkapps\Shared\BenchmarkConfigurationHelpers.cs
perf\benchmarkapps\Shared\BenchmarkServiceImpl.cs = perf\benchmarkapps\Shared\BenchmarkServiceImpl.cs
perf\benchmarkapps\Shared\messages.proto = perf\benchmarkapps\Shared\messages.proto
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.AspNetCore.Microbenchmarks", "perf\Grpc.AspNetCore.Microbenchmarks\Grpc.AspNetCore.Microbenchmarks.csproj", "{98500D54-FC3F-4A42-B74D-51930C19B175}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InteropTestsWebsite", "testassets\InteropTestsWebsite\InteropTestsWebsite.csproj", "{A551D7B1-D75A-43F0-A8E3-BAEA5EDF616A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BenchmarkWorkerWebsite", "testassets\BenchmarkWorkerWebsite\BenchmarkWorkerWebsite.csproj", "{C3D6C3BD-4E56-4B0F-88FD-4F2D68F0CD25}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Certs", "Certs", "{39320CA8-D8F0-45B6-B704-A04C16870226}"
ProjectSection(SolutionItems) = preProject
perf\benchmarkapps\Shared\Certs\testCert.pfx = perf\benchmarkapps\Shared\Certs\testCert.pfx
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.AspNetCore.Server.Reflection", "src\Grpc.AspNetCore.Server.Reflection\Grpc.AspNetCore.Server.Reflection.csproj", "{55813F20-1269-4B19-B03E-7E4A90148F92}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InteropTestsClient", "testassets\InteropTestsClient\InteropTestsClient.csproj", "{291E5BA5-608D-406D-A2DB-389412D907F3}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Certs", "Certs", "{743F8EC2-004E-4640-B04F-5BAFDA8BF112}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "InteropTests", "InteropTests", "{50CF39FF-2644-4B5F-BE1A-B57487B9723B}"
ProjectSection(SolutionItems) = preProject
testassets\Certs\InteropTests\ca.pem = testassets\Certs\InteropTests\ca.pem
testassets\Certs\InteropTests\README.md = testassets\Certs\InteropTests\README.md
testassets\Certs\InteropTests\server1.key = testassets\Certs\InteropTests\server1.key
testassets\Certs\InteropTests\server1.pem = testassets\Certs\InteropTests\server1.pem
testassets\Certs\InteropTests\server1.pfx = testassets\Certs\InteropTests\server1.pfx
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "grpc", "grpc", "{6DC078D2-8FB1-4685-B9BE-61F1C0ED8053}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "testing", "testing", "{88AC787E-603C-48C3-AEBA-D90F3E2142CA}"
ProjectSection(SolutionItems) = preProject
testassets\Proto\grpc\testing\empty.proto = testassets\Proto\grpc\testing\empty.proto
testassets\Proto\grpc\testing\messages.proto = testassets\Proto\grpc\testing\messages.proto
testassets\Proto\grpc\testing\test.proto = testassets\Proto\grpc\testing\test.proto
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InteropTestsNativeServer", "testassets\InteropTestsNativeServer\InteropTestsNativeServer.csproj", "{D15CAEF6-0A5D-416E-B6F7-DE75C4B1D89B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-grpc", "src\dotnet-grpc\dotnet-grpc.csproj", "{EBD5D978-1519-45ED-AC20-EC43C7FA552C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-grpc.Tests", "test\dotnet-grpc.Tests\dotnet-grpc.Tests.csproj", "{265CD0AA-A1BD-40B8-A1E6-B3CB5F7591B8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.AspNetCore.Server.ClientFactory", "src\Grpc.AspNetCore.Server.ClientFactory\Grpc.AspNetCore.Server.ClientFactory.csproj", "{BF9F5674-2BC3-446E-BBEA-3055A4A2B889}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.AspNetCore.Server.ClientFactory.Tests", "test\Grpc.AspNetCore.Server.ClientFactory.Tests\Grpc.AspNetCore.Server.ClientFactory.Tests.csproj", "{4306E048-9D81-44A8-8069-2C294289FC00}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Net.Client", "src\Grpc.Net.Client\Grpc.Net.Client.csproj", "{095F2B46-16DC-4A2E-A075-A0373D902294}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Net.Client.Tests", "test\Grpc.Net.Client.Tests\Grpc.Net.Client.Tests.csproj", "{7C299E2C-A5FE-439D-A346-2A676302BD04}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Net.ClientFactory", "src\Grpc.Net.ClientFactory\Grpc.Net.ClientFactory.csproj", "{F68DBD76-196A-4F55-BBEB-97278655017F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Net.ClientFactory.Tests", "test\Grpc.Net.ClientFactory.Tests\Grpc.Net.ClientFactory.Tests.csproj", "{0C98BD64-8A57-46A1-B47B-EAF260DEE25A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.AspNetCore", "src\Grpc.AspNetCore\Grpc.AspNetCore.csproj", "{F6CA82C9-85C6-4A5F-B892-4DF8A20B1C05}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Net.Common", "src\Grpc.Net.Common\Grpc.Net.Common.csproj", "{69C50655-71EE-4E69-BC2C-ABCA568F6E76}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GrpcAspNetCoreServer", "perf\benchmarkapps\GrpcAspNetCoreServer\GrpcAspNetCoreServer.csproj", "{1D9AB69D-244C-4871-867E-DCEC52B552A4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GrpcCoreServer", "perf\benchmarkapps\GrpcCoreServer\GrpcCoreServer.csproj", "{781111FC-8F3C-433E-BC96-D88ADAEE3064}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Net.Client.Web", "src\Grpc.Net.Client.Web\Grpc.Net.Client.Web.csproj", "{429EB088-94FF-4F06-8E54-72157089C8C3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.AspNetCore.Web", "src\Grpc.AspNetCore.Web\Grpc.AspNetCore.Web.csproj", "{778DB6EE-E5B2-4875-A209-40010B5A3E21}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.AspNetCore.HealthChecks", "src\Grpc.AspNetCore.HealthChecks\Grpc.AspNetCore.HealthChecks.csproj", "{39A9F2B5-2541-423E-83C9-46C7BFF53F41}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{89ED416F-92F1-4425-9379-D4E76A285860}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{89ED416F-92F1-4425-9379-D4E76A285860}.Debug|Any CPU.Build.0 = Debug|Any CPU
{89ED416F-92F1-4425-9379-D4E76A285860}.Release|Any CPU.ActiveCfg = Release|Any CPU
{89ED416F-92F1-4425-9379-D4E76A285860}.Release|Any CPU.Build.0 = Release|Any CPU
{278B1311-41BF-4345-947E-7B70E277FC3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{278B1311-41BF-4345-947E-7B70E277FC3C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{278B1311-41BF-4345-947E-7B70E277FC3C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{278B1311-41BF-4345-947E-7B70E277FC3C}.Release|Any CPU.Build.0 = Release|Any CPU
{B190F61D-854C-4EE1-9532-B81AB3215F90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B190F61D-854C-4EE1-9532-B81AB3215F90}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B190F61D-854C-4EE1-9532-B81AB3215F90}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B190F61D-854C-4EE1-9532-B81AB3215F90}.Release|Any CPU.Build.0 = Release|Any CPU
{7B95289B-4992-4C0D-B26F-8EC58F81FC96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7B95289B-4992-4C0D-B26F-8EC58F81FC96}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7B95289B-4992-4C0D-B26F-8EC58F81FC96}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7B95289B-4992-4C0D-B26F-8EC58F81FC96}.Release|Any CPU.Build.0 = Release|Any CPU
{B10D4986-25D2-4414-B500-627D89505914}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B10D4986-25D2-4414-B500-627D89505914}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B10D4986-25D2-4414-B500-627D89505914}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B10D4986-25D2-4414-B500-627D89505914}.Release|Any CPU.Build.0 = Release|Any CPU
{98500D54-FC3F-4A42-B74D-51930C19B175}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{98500D54-FC3F-4A42-B74D-51930C19B175}.Debug|Any CPU.Build.0 = Debug|Any CPU
{98500D54-FC3F-4A42-B74D-51930C19B175}.Release|Any CPU.ActiveCfg = Release|Any CPU
{98500D54-FC3F-4A42-B74D-51930C19B175}.Release|Any CPU.Build.0 = Release|Any CPU
{A551D7B1-D75A-43F0-A8E3-BAEA5EDF616A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A551D7B1-D75A-43F0-A8E3-BAEA5EDF616A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A551D7B1-D75A-43F0-A8E3-BAEA5EDF616A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A551D7B1-D75A-43F0-A8E3-BAEA5EDF616A}.Release|Any CPU.Build.0 = Release|Any CPU
{C3D6C3BD-4E56-4B0F-88FD-4F2D68F0CD25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C3D6C3BD-4E56-4B0F-88FD-4F2D68F0CD25}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C3D6C3BD-4E56-4B0F-88FD-4F2D68F0CD25}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C3D6C3BD-4E56-4B0F-88FD-4F2D68F0CD25}.Release|Any CPU.Build.0 = Release|Any CPU
{55813F20-1269-4B19-B03E-7E4A90148F92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{55813F20-1269-4B19-B03E-7E4A90148F92}.Debug|Any CPU.Build.0 = Debug|Any CPU
{55813F20-1269-4B19-B03E-7E4A90148F92}.Release|Any CPU.ActiveCfg = Release|Any CPU
{55813F20-1269-4B19-B03E-7E4A90148F92}.Release|Any CPU.Build.0 = Release|Any CPU
{291E5BA5-608D-406D-A2DB-389412D907F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{291E5BA5-608D-406D-A2DB-389412D907F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{291E5BA5-608D-406D-A2DB-389412D907F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{291E5BA5-608D-406D-A2DB-389412D907F3}.Release|Any CPU.Build.0 = Release|Any CPU
{D15CAEF6-0A5D-416E-B6F7-DE75C4B1D89B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D15CAEF6-0A5D-416E-B6F7-DE75C4B1D89B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D15CAEF6-0A5D-416E-B6F7-DE75C4B1D89B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D15CAEF6-0A5D-416E-B6F7-DE75C4B1D89B}.Release|Any CPU.Build.0 = Release|Any CPU
{EBD5D978-1519-45ED-AC20-EC43C7FA552C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EBD5D978-1519-45ED-AC20-EC43C7FA552C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EBD5D978-1519-45ED-AC20-EC43C7FA552C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EBD5D978-1519-45ED-AC20-EC43C7FA552C}.Release|Any CPU.Build.0 = Release|Any CPU
{265CD0AA-A1BD-40B8-A1E6-B3CB5F7591B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{265CD0AA-A1BD-40B8-A1E6-B3CB5F7591B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{265CD0AA-A1BD-40B8-A1E6-B3CB5F7591B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{265CD0AA-A1BD-40B8-A1E6-B3CB5F7591B8}.Release|Any CPU.Build.0 = Release|Any CPU
{BF9F5674-2BC3-446E-BBEA-3055A4A2B889}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BF9F5674-2BC3-446E-BBEA-3055A4A2B889}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BF9F5674-2BC3-446E-BBEA-3055A4A2B889}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BF9F5674-2BC3-446E-BBEA-3055A4A2B889}.Release|Any CPU.Build.0 = Release|Any CPU
{4306E048-9D81-44A8-8069-2C294289FC00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4306E048-9D81-44A8-8069-2C294289FC00}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4306E048-9D81-44A8-8069-2C294289FC00}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4306E048-9D81-44A8-8069-2C294289FC00}.Release|Any CPU.Build.0 = Release|Any CPU
{095F2B46-16DC-4A2E-A075-A0373D902294}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{095F2B46-16DC-4A2E-A075-A0373D902294}.Debug|Any CPU.Build.0 = Debug|Any CPU
{095F2B46-16DC-4A2E-A075-A0373D902294}.Release|Any CPU.ActiveCfg = Release|Any CPU
{095F2B46-16DC-4A2E-A075-A0373D902294}.Release|Any CPU.Build.0 = Release|Any CPU
{7C299E2C-A5FE-439D-A346-2A676302BD04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C299E2C-A5FE-439D-A346-2A676302BD04}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C299E2C-A5FE-439D-A346-2A676302BD04}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C299E2C-A5FE-439D-A346-2A676302BD04}.Release|Any CPU.Build.0 = Release|Any CPU
{F68DBD76-196A-4F55-BBEB-97278655017F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F68DBD76-196A-4F55-BBEB-97278655017F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F68DBD76-196A-4F55-BBEB-97278655017F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F68DBD76-196A-4F55-BBEB-97278655017F}.Release|Any CPU.Build.0 = Release|Any CPU
{0C98BD64-8A57-46A1-B47B-EAF260DEE25A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0C98BD64-8A57-46A1-B47B-EAF260DEE25A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0C98BD64-8A57-46A1-B47B-EAF260DEE25A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0C98BD64-8A57-46A1-B47B-EAF260DEE25A}.Release|Any CPU.Build.0 = Release|Any CPU
{F6CA82C9-85C6-4A5F-B892-4DF8A20B1C05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F6CA82C9-85C6-4A5F-B892-4DF8A20B1C05}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F6CA82C9-85C6-4A5F-B892-4DF8A20B1C05}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F6CA82C9-85C6-4A5F-B892-4DF8A20B1C05}.Release|Any CPU.Build.0 = Release|Any CPU
{69C50655-71EE-4E69-BC2C-ABCA568F6E76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{69C50655-71EE-4E69-BC2C-ABCA568F6E76}.Debug|Any CPU.Build.0 = Debug|Any CPU
{69C50655-71EE-4E69-BC2C-ABCA568F6E76}.Release|Any CPU.ActiveCfg = Release|Any CPU
{69C50655-71EE-4E69-BC2C-ABCA568F6E76}.Release|Any CPU.Build.0 = Release|Any CPU
{1D9AB69D-244C-4871-867E-DCEC52B552A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1D9AB69D-244C-4871-867E-DCEC52B552A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1D9AB69D-244C-4871-867E-DCEC52B552A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1D9AB69D-244C-4871-867E-DCEC52B552A4}.Release|Any CPU.Build.0 = Release|Any CPU
{781111FC-8F3C-433E-BC96-D88ADAEE3064}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{781111FC-8F3C-433E-BC96-D88ADAEE3064}.Debug|Any CPU.Build.0 = Debug|Any CPU
{781111FC-8F3C-433E-BC96-D88ADAEE3064}.Release|Any CPU.ActiveCfg = Release|Any CPU
{781111FC-8F3C-433E-BC96-D88ADAEE3064}.Release|Any CPU.Build.0 = Release|Any CPU
{429EB088-94FF-4F06-8E54-72157089C8C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{429EB088-94FF-4F06-8E54-72157089C8C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{429EB088-94FF-4F06-8E54-72157089C8C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{429EB088-94FF-4F06-8E54-72157089C8C3}.Release|Any CPU.Build.0 = Release|Any CPU
{778DB6EE-E5B2-4875-A209-40010B5A3E21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{778DB6EE-E5B2-4875-A209-40010B5A3E21}.Debug|Any CPU.Build.0 = Debug|Any CPU
{778DB6EE-E5B2-4875-A209-40010B5A3E21}.Release|Any CPU.ActiveCfg = Release|Any CPU
{778DB6EE-E5B2-4875-A209-40010B5A3E21}.Release|Any CPU.Build.0 = Release|Any CPU
{39A9F2B5-2541-423E-83C9-46C7BFF53F41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{39A9F2B5-2541-423E-83C9-46C7BFF53F41}.Debug|Any CPU.Build.0 = Debug|Any CPU
{39A9F2B5-2541-423E-83C9-46C7BFF53F41}.Release|Any CPU.ActiveCfg = Release|Any CPU
{39A9F2B5-2541-423E-83C9-46C7BFF53F41}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{89ED416F-92F1-4425-9379-D4E76A285860} = {8C62055F-8CD7-4859-9001-634D544DF2AE}
{278B1311-41BF-4345-947E-7B70E277FC3C} = {CECC4AE8-9C4E-4727-939B-517CC2E58D65}
{B190F61D-854C-4EE1-9532-B81AB3215F90} = {CECC4AE8-9C4E-4727-939B-517CC2E58D65}
{59C7B1F0-EE4D-4098-8596-0ADDBC305234} = {CECC4AE8-9C4E-4727-939B-517CC2E58D65}
{BF1393D4-6099-4EF9-85BB-7EE6CBEB920C} = {59C7B1F0-EE4D-4098-8596-0ADDBC305234}
{7B95289B-4992-4C0D-B26F-8EC58F81FC96} = {59C7B1F0-EE4D-4098-8596-0ADDBC305234}
{1B8B6117-CE39-4580-BAFA-D8026102767A} = {4163E1B3-4D75-46B4-9107-9A158FD708FC}
{B10D4986-25D2-4414-B500-627D89505914} = {1B8B6117-CE39-4580-BAFA-D8026102767A}
{310E5783-455A-4D09-A7AE-39DC2AB09504} = {1B8B6117-CE39-4580-BAFA-D8026102767A}
{98500D54-FC3F-4A42-B74D-51930C19B175} = {4163E1B3-4D75-46B4-9107-9A158FD708FC}
{A551D7B1-D75A-43F0-A8E3-BAEA5EDF616A} = {59C7B1F0-EE4D-4098-8596-0ADDBC305234}
{C3D6C3BD-4E56-4B0F-88FD-4F2D68F0CD25} = {59C7B1F0-EE4D-4098-8596-0ADDBC305234}
{39320CA8-D8F0-45B6-B704-A04C16870226} = {310E5783-455A-4D09-A7AE-39DC2AB09504}
{55813F20-1269-4B19-B03E-7E4A90148F92} = {8C62055F-8CD7-4859-9001-634D544DF2AE}
{291E5BA5-608D-406D-A2DB-389412D907F3} = {59C7B1F0-EE4D-4098-8596-0ADDBC305234}
{743F8EC2-004E-4640-B04F-5BAFDA8BF112} = {59C7B1F0-EE4D-4098-8596-0ADDBC305234}
{50CF39FF-2644-4B5F-BE1A-B57487B9723B} = {743F8EC2-004E-4640-B04F-5BAFDA8BF112}
{6DC078D2-8FB1-4685-B9BE-61F1C0ED8053} = {BF1393D4-6099-4EF9-85BB-7EE6CBEB920C}
{88AC787E-603C-48C3-AEBA-D90F3E2142CA} = {6DC078D2-8FB1-4685-B9BE-61F1C0ED8053}
{D15CAEF6-0A5D-416E-B6F7-DE75C4B1D89B} = {59C7B1F0-EE4D-4098-8596-0ADDBC305234}
{EBD5D978-1519-45ED-AC20-EC43C7FA552C} = {8C62055F-8CD7-4859-9001-634D544DF2AE}
{265CD0AA-A1BD-40B8-A1E6-B3CB5F7591B8} = {CECC4AE8-9C4E-4727-939B-517CC2E58D65}
{BF9F5674-2BC3-446E-BBEA-3055A4A2B889} = {8C62055F-8CD7-4859-9001-634D544DF2AE}
{4306E048-9D81-44A8-8069-2C294289FC00} = {CECC4AE8-9C4E-4727-939B-517CC2E58D65}
{095F2B46-16DC-4A2E-A075-A0373D902294} = {8C62055F-8CD7-4859-9001-634D544DF2AE}
{7C299E2C-A5FE-439D-A346-2A676302BD04} = {CECC4AE8-9C4E-4727-939B-517CC2E58D65}
{F68DBD76-196A-4F55-BBEB-97278655017F} = {8C62055F-8CD7-4859-9001-634D544DF2AE}
{0C98BD64-8A57-46A1-B47B-EAF260DEE25A} = {CECC4AE8-9C4E-4727-939B-517CC2E58D65}
{F6CA82C9-85C6-4A5F-B892-4DF8A20B1C05} = {8C62055F-8CD7-4859-9001-634D544DF2AE}
{69C50655-71EE-4E69-BC2C-ABCA568F6E76} = {8C62055F-8CD7-4859-9001-634D544DF2AE}
{1D9AB69D-244C-4871-867E-DCEC52B552A4} = {1B8B6117-CE39-4580-BAFA-D8026102767A}
{781111FC-8F3C-433E-BC96-D88ADAEE3064} = {1B8B6117-CE39-4580-BAFA-D8026102767A}
{429EB088-94FF-4F06-8E54-72157089C8C3} = {8C62055F-8CD7-4859-9001-634D544DF2AE}
{778DB6EE-E5B2-4875-A209-40010B5A3E21} = {8C62055F-8CD7-4859-9001-634D544DF2AE}
{39A9F2B5-2541-423E-83C9-46C7BFF53F41} = {8C62055F-8CD7-4859-9001-634D544DF2AE}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {CD5C2B19-49B4-480A-990C-36D98A719B07}
EndGlobalSection
EndGlobal

View File

@ -1,90 +0,0 @@
<Solution>
<Folder Name="/perf/">
<Project Path="perf/Grpc.AspNetCore.Microbenchmarks/Grpc.AspNetCore.Microbenchmarks.csproj" />
</Folder>
<Folder Name="/perf/benchmarkapps/">
<Project Path="perf/benchmarkapps/GrpcAspNetCoreServer/GrpcAspNetCoreServer.csproj" />
<Project Path="perf/benchmarkapps/GrpcClient/GrpcClient.csproj" />
<Project Path="perf/benchmarkapps/GrpcCoreServer/GrpcCoreServer.csproj" />
<Project Path="perf/benchmarkapps/QpsWorker/QpsWorker.csproj" />
</Folder>
<Folder Name="/perf/benchmarkapps/Shared/">
<File Path="perf/benchmarkapps/Shared/BenchmarkConfigurationHelpers.cs" />
<File Path="perf/benchmarkapps/Shared/BenchmarkServiceImpl.cs" />
<File Path="perf/benchmarkapps/Shared/benchmark_service.proto" />
<File Path="perf/benchmarkapps/Shared/messages.proto" />
</Folder>
<Folder Name="/perf/benchmarkapps/Shared/Certs/">
<File Path="perf/benchmarkapps/Shared/Certs/testCert.pfx" />
</Folder>
<Folder Name="/src/">
<Project Path="src/dotnet-grpc/dotnet-grpc.csproj" />
<Project Path="src/Grpc.AspNetCore.HealthChecks/Grpc.AspNetCore.HealthChecks.csproj" />
<Project Path="src/Grpc.AspNetCore.Server.ClientFactory/Grpc.AspNetCore.Server.ClientFactory.csproj" />
<Project Path="src/Grpc.AspNetCore.Server.Reflection/Grpc.AspNetCore.Server.Reflection.csproj" />
<Project Path="src/Grpc.AspNetCore.Server/Grpc.AspNetCore.Server.csproj" />
<Project Path="src/Grpc.AspNetCore.Web/Grpc.AspNetCore.Web.csproj" />
<Project Path="src/Grpc.AspNetCore/Grpc.AspNetCore.csproj" />
<Project Path="src/Grpc.Auth/Grpc.Auth.csproj" />
<Project Path="src/Grpc.Core.Api/Grpc.Core.Api.csproj" />
<Project Path="src/Grpc.HealthCheck/Grpc.HealthCheck.csproj" />
<Project Path="src/Grpc.Net.Client.Web/Grpc.Net.Client.Web.csproj" />
<Project Path="src/Grpc.Net.Client/Grpc.Net.Client.csproj" />
<Project Path="src/Grpc.Net.ClientFactory/Grpc.Net.ClientFactory.csproj" />
<Project Path="src/Grpc.Net.Common/Grpc.Net.Common.csproj" />
<Project Path="src/Grpc.Reflection/Grpc.Reflection.csproj" />
<Project Path="src/Grpc.StatusProto/Grpc.StatusProto.csproj" />
</Folder>
<Folder Name="/tests/">
<Project Path="test/dotnet-grpc.Tests/dotnet-grpc.Tests.csproj" />
<Project Path="test/FunctionalTests/Grpc.AspNetCore.FunctionalTests.csproj" />
<Project Path="test/Grpc.AspNetCore.Server.ClientFactory.Tests/Grpc.AspNetCore.Server.ClientFactory.Tests.csproj" />
<Project Path="test/Grpc.AspNetCore.Server.Tests/Grpc.AspNetCore.Server.Tests.csproj" />
<Project Path="test/Grpc.Core.Api.Tests/Grpc.Core.Api.Tests.csproj" />
<Project Path="test/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj" />
<Project Path="test/Grpc.Net.Client.Tests/Grpc.Net.Client.Tests.csproj" />
<Project Path="test/Grpc.Net.Client.Web.Tests/Grpc.Net.Client.Web.Tests.csproj" />
<Project Path="test/Grpc.Net.ClientFactory.Tests/Grpc.Net.ClientFactory.Tests.csproj" />
<Project Path="test/Grpc.Reflection.Tests/Grpc.Reflection.Tests.csproj" />
<Project Path="test/Grpc.StatusProto.Tests/Grpc.StatusProto.Tests.csproj" />
</Folder>
<Folder Name="/tests/testassets/">
<Project Path="testassets/BenchmarkWorkerWebsite/BenchmarkWorkerWebsite.csproj" />
<Project Path="testassets/FunctionalTestsWebsite/FunctionalTestsWebsite.csproj" />
<Project Path="testassets/InteropTestsClient/InteropTestsClient.csproj" />
<Project Path="testassets/InteropTestsGrpcWebClient/InteropTestsGrpcWebClient.csproj" />
<Project Path="testassets/InteropTestsGrpcWebWebsite/InteropTestsGrpcWebWebsite.csproj" />
<Project Path="testassets/InteropTestsNativeServer/InteropTestsNativeServer.csproj" />
<Project Path="testassets/InteropTestsWebsite/InteropTestsWebsite.csproj" />
<Project Path="testassets/LinkerTestsClient/LinkerTestsClient.csproj" />
<Project Path="testassets/LinkerTestsWebsite/LinkerTestsWebsite.csproj" />
</Folder>
<Folder Name="/tests/testassets/Certs/" />
<Folder Name="/tests/testassets/Certs/InteropTests/">
<File Path="testassets/Certs/InteropTests/ca.pem" />
<File Path="testassets/Certs/InteropTests/README.md" />
<File Path="testassets/Certs/InteropTests/server1.key" />
<File Path="testassets/Certs/InteropTests/server1.pem" />
<File Path="testassets/Certs/InteropTests/server1.pfx" />
</Folder>
<Folder Name="/tests/testassets/Proto/">
<File Path="examples/Proto/race.proto" />
<File Path="testassets/Proto/any.proto" />
<File Path="testassets/Proto/authorize.proto" />
<File Path="testassets/Proto/chat.proto" />
<File Path="testassets/Proto/compression.proto" />
<File Path="testassets/Proto/count.proto" />
<File Path="testassets/Proto/greet.proto" />
<File Path="testassets/Proto/lifetime.proto" />
<File Path="testassets/Proto/nested.proto" />
<File Path="testassets/Proto/singleton.proto" />
<File Path="testassets/Proto/streaming.proto" />
<File Path="testassets/Proto/unimplemented.proto" />
</Folder>
<Folder Name="/tests/testassets/Proto/grpc/" />
<Folder Name="/tests/testassets/Proto/grpc/testing/">
<File Path="testassets/Proto/grpc/testing/empty.proto" />
<File Path="testassets/Proto/grpc/testing/messages.proto" />
<File Path="testassets/Proto/grpc/testing/test.proto" />
</Folder>
</Solution>

View File

@ -8,17 +8,11 @@ See [CONTRIBUTING.md](https://github.com/grpc/grpc-community/blob/master/CONTRIB
for general contribution guidelines.
## Maintainers (in alphabetical order)
- [adityamandaleeka](https://github.com/adityamandaleeka), Microsoft Corporation
- [amcasey](https://github.com/amcasey), Microsoft Corporation
- [anurse](https://github.com/anurse), Microsoft Corporation
- [apolcyn](https://github.com/apolcyn), Google LLC
- [benjaminpetit](https://github.com/benjaminpetit), Microsoft Corporation
- [BrennanConroy](https://github.com/BrennanConroy), Microsoft Corporation
- [davidfowl](https://github.com/davidfowl), Microsoft Corporation
- [JamesNK](https://github.com/JamesNK), Microsoft Corporation
- [mgravell](https://github.com/mgravell), Microsoft Corporation
- [ReubenBond](https://github.com/ReubenBond), Microsoft Corporation
- [stanley-cheung](https://github.com/stanley-cheung), Google LLC
- [jtattermusch](https://github.com/jtattermusch), Google LLC
- [JunTaoLuo](https://github.com/JunTaoLuo), Microsoft Corporation
## Emeritus Maintainers (in alphabetical order)
- [jtattermusch](https://github.com/jtattermusch)
- [JunTaoLuo](https://github.com/JunTaoLuo)

View File

@ -1,23 +1,22 @@
# gRPC for .NET
## Available now on .NET Core 3.0!
gRPC is a modern, open source, high-performance remote procedure call (RPC) framework that can run anywhere. gRPC enables client and server applications to communicate transparently, and simplifies the building of connected systems.
gRPC functionality for .NET Core 3.0 or later includes:
gRPC functionality for .NET Core 3.0 includes:
* [Grpc.AspNetCore](https://www.nuget.org/packages/Grpc.AspNetCore) &ndash; An ASP.NET Core framework for hosting gRPC services. gRPC on ASP.NET Core integrates with standard ASP.NET Core features like logging, dependency injection (DI), authentication and authorization.
* [Grpc.Net.Client](https://www.nuget.org/packages/Grpc.Net.Client) &ndash; A gRPC client for .NET Core that builds upon the familiar `HttpClient`. The client uses new HTTP/2 functionality in .NET Core.
* [Grpc.Net.ClientFactory](https://www.nuget.org/packages/Grpc.Net.ClientFactory) &ndash; gRPC client integration with `HttpClientFactory`. The client factory allows gRPC clients to be centrally configured and injected into your app with DI.
Please note that gRPC for .NET does not replace [gRPC for C#](https://github.com/grpc/grpc/tree/master/src/csharp) (gRPC C# API over native C-core binaries). These implementations coexist and share many of the same APIs to avoid lock-in. There are currently no plans for one implementation to replace the other one. gRPC for C# is the recommended solution for frameworks that gRPC for .NET does not support, such as .NET Framework.
For more information, see [An introduction to gRPC on .NET](https://docs.microsoft.com/aspnet/core/grpc/).
## gRPC for .NET is now the recommended implementation!
Starting from May 2021, gRPC for .NET is the recommended implemention of gRPC for C#. The original [gRPC for C#](https://github.com/grpc/grpc/tree/master/src/csharp) implementation (distributed as the `Grpc.Core` nuget package) is now in maintenance mode and will be deprecated in the future.
See [blogpost](https://grpc.io/blog/grpc-csharp-future/) for more details.
## To start using gRPC for .NET
The best place to start using gRPC for .NET is the gRPC template that comes with .NET Core 3.0 or later. Use the template to [create a gRPC service website and client](https://docs.microsoft.com/aspnet/core/tutorials/grpc/grpc-start).
The best place to start using gRPC for .NET is the gRPC template that comes with .NET Core 3.0. Use the template to [create a gRPC service website and client](https://docs.microsoft.com/aspnet/core/tutorials/grpc/grpc-start).
For additional examples of using gRPC in .NET refer to https://github.com/grpc/grpc-dotnet/tree/master/examples.
@ -62,20 +61,14 @@ startvs.cmd
To build from the command line:
```
dotnet build Grpc.DotNet.slnx
dotnet build Grpc.DotNet.sln
```
To run tests from the command line:
```
dotnet test Grpc.DotNet.slnx
dotnet test Grpc.DotNet.sln
```
### Alternative implementation using Code-First (external library)
An alternative way to use gRPC in .NET is to define the Protobuf contracts directly in C# using [protobuf-net](https://github.com/protobuf-net/protobuf-net.Grpc).
For more information, see the documentation on [learn.microsoft.com](https://learn.microsoft.com/aspnet/core/grpc/code-first) or the [protobuf-net.Grpc website](https://protobuf-net.github.io/protobuf-net.Grpc/).
## To contribute
Contributions are welcome!

27
build/dependencies.props Normal file
View File

@ -0,0 +1,27 @@
<Project>
<PropertyGroup>
<BenchmarkDotNetPackageVersion>0.11.3</BenchmarkDotNetPackageVersion>
<CommandLineParserPackageVersion>2.3.0</CommandLineParserPackageVersion>
<GoogleProtobufPackageVersion>3.11.4</GoogleProtobufPackageVersion>
<GrpcDotNetPackageVersion>2.27.0-pre1</GrpcDotNetPackageVersion> <!-- Only use for example projects -->
<GrpcPackageVersion>2.27.0</GrpcPackageVersion>
<MicrosoftAspNetCorePackageVersion>3.1.2</MicrosoftAspNetCorePackageVersion>
<MicrosoftAspNetCoreBlazorPackageVersion>3.2.0-preview1.20073.1</MicrosoftAspNetCoreBlazorPackageVersion>
<MicrosoftBuildLocatorPackageVersion>1.2.2</MicrosoftBuildLocatorPackageVersion>
<MicrosoftBuildPackageVersion>16.0.461</MicrosoftBuildPackageVersion>
<MicrosoftCodeAnalysisFxCopAnalyzersPackageVersion>2.9.4</MicrosoftCodeAnalysisFxCopAnalyzersPackageVersion>
<MicrosoftExtensionsPackageVersion>2.1.1</MicrosoftExtensionsPackageVersion>
<MicrosoftExtensions30PackageVersion>3.0.0</MicrosoftExtensions30PackageVersion>
<MicrosoftNETTestSdkPackageVersion>16.2.0</MicrosoftNETTestSdkPackageVersion>
<MicrosoftSourceLinkGitHubPackageVersion>1.0.0-beta2-19367-01</MicrosoftSourceLinkGitHubPackageVersion>
<MicrosoftWin32RegistryLinePackageVersion>4.6.0</MicrosoftWin32RegistryLinePackageVersion>
<MoqPackageVersion>4.10.0</MoqPackageVersion>
<NewtonsoftJsonPackageVersion>12.0.2</NewtonsoftJsonPackageVersion>
<NunitPackageVersion>3.12.0</NunitPackageVersion>
<Nunit3TestAdapterPackageVersion>3.13.0</Nunit3TestAdapterPackageVersion>
<OpenTelemetryPackageVersion>0.2.0-alpha.100</OpenTelemetryPackageVersion>
<SystemCommandLinePackageVersion>0.3.0-alpha.19405.1</SystemCommandLinePackageVersion>
<SystemDiagnosticsDiagnosticSourcePackageVersion>4.5.1</SystemDiagnosticsDiagnosticSourcePackageVersion>
<SystemSecurityPrincipalWindowsPackageVersion>4.6.0</SystemSecurityPrincipalWindowsPackageVersion>
</PropertyGroup>
</Project>

View File

@ -27,11 +27,4 @@ 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 .NET 8 SDK to run 8.0 test targets
$install_script_path -v 8.0.412 -i $dotnet_install_path
# Install .NET 9 SDK to run 9.0 test targets
$install_script_path -v 9.0.303 -i $dotnet_install_path
# Install .NET version specified by global.json
$install_script_path -v $sdk_version -i $dotnet_install_path

21
build/sources.props Normal file
View File

@ -0,0 +1,21 @@
<Project>
<PropertyGroup Label="RestoreSources">
<RestoreSources>
$(RestoreSources);
https://api.nuget.org/v3/index.json;
https://dotnetfeed.blob.core.windows.net/aspnet-aspnetcore/index.json;
https://dotnetfeed.blob.core.windows.net/aspnet-extensions/index.json;
https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json;
https://dotnet.myget.org/F/roslyn/api/v3/index.json;
</RestoreSources>
<RestoreSources Condition="Exists('$(MSBuildThisFileDirectory)feed')">
$(RestoreSources);
$(MSBuildThisFileDirectory)feed;
</RestoreSources>
<!-- The following is used to ingest nightly gRPC packages -->
<RestoreSources>
$(RestoreSources);
https://grpc.jfrog.io/grpc/api/nuget/v3/grpc-nuget-dev;
</RestoreSources>
</PropertyGroup>
</Project>

View File

@ -1,32 +0,0 @@
#!/bin/bash
# Copyright 2022 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.
# Update Grpc.Core.Api's VersionInfo.cs with versions from version.props
set -e
cd "$(dirname "$0")"
# retrieve version strings from version.props
PACKAGE_VERSION=$(grep -o '<GrpcDotnetVersion>.*</GrpcDotnetVersion>' version.props | sed 's/<GrpcDotnetVersion>//' | sed 's/<\/GrpcDotnetVersion>//')
ASSEMBLY_VERSION=$(grep -o '<GrpcDotnetAssemblyVersion>.*</GrpcDotnetAssemblyVersion>' version.props | sed 's/<GrpcDotnetAssemblyVersion>//' | sed 's/<\/GrpcDotnetAssemblyVersion>//')
ASSEMBLY_FILE_VERSION=$(grep -o '<GrpcDotnetAssemblyFileVersion>.*</GrpcDotnetAssemblyFileVersion>' version.props | sed 's/<GrpcDotnetAssemblyFileVersion>//' | sed 's/<\/GrpcDotnetAssemblyFileVersion>//')
# update the contents of src/Grpc.Core.Api/VersionInfo.cs with the version strings
sed -i "s/CurrentVersion = \".*\"/CurrentVersion = \"${PACKAGE_VERSION}\"/g" ../src/Grpc.Core.Api/VersionInfo.cs
sed -i "s/CurrentAssemblyVersion = \".*\"/CurrentAssemblyVersion = \"${ASSEMBLY_VERSION}\"/g" ../src/Grpc.Core.Api/VersionInfo.cs
sed -i "s/CurrentAssemblyFileVersion = \".*\"/CurrentAssemblyFileVersion = \"${ASSEMBLY_FILE_VERSION}\"/g" ../src/Grpc.Core.Api/VersionInfo.cs
echo "Updated version strings in src/Grpc.Core.Api/VersionInfo.cs"

View File

@ -2,13 +2,13 @@
<PropertyGroup>
<!-- package version of grpc-dotnet -->
<GrpcDotnetVersion>2.66.0-dev</GrpcDotnetVersion>
<GrpcDotnetVersion>2.28.0-pre2</GrpcDotnetVersion>
<!-- assembly version of grpc-dotnet -->
<GrpcDotnetAssemblyVersion>2.0.0.0</GrpcDotnetAssemblyVersion>
<!-- file version of all grpc-dotnet -->
<GrpcDotnetAssemblyFileVersion>2.66.0.0</GrpcDotnetAssemblyFileVersion>
<GrpcDotnetAssemblyFileVersion>2.28.0.0</GrpcDotnetAssemblyFileVersion>
</PropertyGroup>
</Project>

View File

@ -22,21 +22,38 @@ echo "Building solution"
dotnet build -c Release
echo "Building examples"
example_solutions=( $( ls examples/**/*.slnx ) )
example_solutions=( $( ls examples/**/*.sln ) )
for example_solution in "${example_solutions[@]}"
do
# dotnet build uses msbuild, and attempts to speed consecutive builds by reusing processes.
# This can become a problem when multiple versions of Grpc.Tools are used between builds.
# The different versions will conflict. Shutdown build processes between builds to avoid conflicts.
# Will be fixed in msbuild 16.5 - https://github.com/microsoft/msbuild/issues/1754
dotnet build-server shutdown
dotnet build $example_solution -c Release
done
echo "Testing solution"
has_failures=false
test_projects=( $( ls test/**/*Tests.csproj ) )
for test_project in "${test_projects[@]}"
do
base_name=$(basename ${test_project%.*})
dotnet test $test_project -c Release --no-build --logger "trx;LogFilePrefix=$base_name" --results-directory artifacts/test-results -- NUnit.ConsoleOut=0 || has_failures=true
# "dotnet test" is hanging when it writes to console for an unknown reason
# Tracking issue at https://github.com/microsoft/vstest/issues/2080
# Write test output to a text file and then write the text file to console as a workaround
{
dotnet test $test_project -c Release -v n --no-build &> ${test_project##*/}.log.txt &&
echo "Success" &&
cat ${test_project##*/}.log.txt
} || {
echo "Failure" &&
cat ${test_project##*/}.log.txt &&
exit 1
}
done
if [ "$has_failures" = true ]; then
exit 1
fi
echo "Finished"

View File

@ -11,60 +11,23 @@ This document summarizes the differences between the two available implementatio
## Criteria for choosing between grpc-dotnet and gRPC C#
Starting from May 2021, gRPC for .NET is the recommended implemention of gRPC for C#.
The original [gRPC C#](https://github.com/grpc/grpc/tree/master/src/csharp) implementation (distributed as the `Grpc.Core` nuget package) is now in maintenance mode and will be deprecated in the future.
See [blogpost](https://grpc.io/blog/grpc-csharp-future/) for more details.
One might choose one or the other implementation mostly for one of these reasons
Here are some key points in which the two implementation differ:
- grpc-dotnet avoids the use of native code (while Grpc.Core use the native C-core library internally)
- grpc-dotnet requires a newer version of .NET (see the "Framework supported" section)
- grpc-dotnet server integrates seamlessly ASP.NET Core (and allows e.g. dependency injection)
- performance (while data we have data that seems to indicate that grpc-dotnet peforms at least as well as Grpc.Core, we strongly encourage to run your own benchmarks if performance matters for your application)
- features available (see breakdown below)
## Frameworks supported
Grpc.Core supports a wide range of .NET versions, including some very old ones. A more detailed overview is [here]( https://github.com/grpc/grpc/tree/master/src/csharp#supported-platforms)
grpc-dotnet uses features only available in modern .NET releases. It doesn't support some older versions of .NET. A detailed summary of .NET versions supported by grpc-dotnet is [here](https://docs.microsoft.com/aspnet/core/grpc/supported-platforms). There is limited support for [grpc-dotnet client support on
legacy .NET Framework](https://docs.microsoft.com/aspnet/core/grpc/netstandard).
- avoid use of native code
- ability to use .NET Core 3 and ASP.NET Core 3 (it's a brand new stack so not everyone will be able to use immediately)
- want seamless integration with ASP.NET Core 3, dependency injection etc.
- features available (see breakdown)
- maturity level
- performance (TODO: add data)
## Comparison of supported features
Beyond the basic RPC functionality, there are a lot of gRPC features that may or may not be supported. The summary
of supported features in both implementation is available in this section.
### Proxyless service mesh (XDS) support
While support for some of the Proxyless service mesh functionality comes "for free" by virtue of using the implementation from C-core native library, we don't officially support the proxyless service mesh functionality in C#.
In grpc-dotnet, we currently don't provide proxyless service mesh support, but it's something that we plan to add in the future. One of the first features we want to integrate is XDS load balancing.
### Load Balancing
grpc-dotnet and Grpc.Core provides basic client load balancing policies PICK_FIRST, ROUND_ROBIN.
Grpc.Core also has implemented two client-lookaside LB policies, but we don't recommend using them:
- grpclb - limited use externally as there's no official implementation of the LB policy. We don't recommend using it as it's been deprecated by the XDS load balancing.
- XDS - Load balancing using the Envoy Universal Data Plane APIs (xDS). It does work in Grpc.Core (because it's implemented in C-core native library), but as noted above, we don't provide official support for the proxyless service mesh functionality in Grpc.Core.
Proxy load balancing is supported by both implementations because load balancing is done by a separate process (e.g. Envoy, ngingx etc.) that proxies the traffic.
grpc-dotnet allows user-provided custom load-balancing policies (= a plugin that provides the load-balancing logic).
Also see:
- https://learn.microsoft.com/aspnet/core/grpc/loadbalancing
- https://github.com/grpc/grpc/blob/master/doc/load-balancing.md
- https://github.com/grpc/grpc/blob/master/doc/naming.md
- https://github.com/grpc/proposal/blob/master/A5-grpclb-in-dns.md
- https://github.com/grpc/proposal/blob/master/A24-lb-policy-config.md
### Service config
Service config is supported by grpc-dotnet and Grpc.Core. Right now, the feature is not that useful
Service config is currently only supported by Grpc.Core. Right now the feature is not that useful
because support for service config encoded in DNS records hasn't been enabled yet by default.
Also see:
@ -82,36 +45,52 @@ Grpc.Core: currently not supported.
Both implementations support client and server interceptors from Grpc.Core.Interceptors namespace. Interceptors operate at post-deserialization and pre-serialization level (no access to binary payloads).
In addition to gRPC-aware interceptors, grpc-dotnet also allows interception at an HTTP/2 level:
In addition to gRPC-aware interceptors, grpc-dotnet also allows interception at a HTTP/2 level:
- Incoming gRPC HTTP/2 requests can be processed using [ASP.NET Core middleware](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware/).
- Outgoing gRPC HTTP/2 requests can be processed using [HttpClient HttpMessageHandlers](https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpmessagehandler).
### Load Balancing
Grpc.Core provides basic client load balancing policies PICK_FIRST, ROUND_ROBIN and client-lookaside LB policies:
- grpclb - limited use externally as there's no official implementation of the LB policy
- XDS - Load balancing using the Envoy Universal Data Plane APIs (xDS). Currently this is work in progress but once ready, it will be the LB of choice for lookaside LB.
grpc-dotnet currently doesn't provide any loadbalancing policies. It is likely that to support the XDS loadbalancing policy, features will need to be added to .NET HttpClient.
Proxy loadbalancing is supported by both implementations because loadbalancing is done by a separate process (e.g. Envoy, ngingx etc.) that proxies the traffic.
None of the implementations currently allow user-provided custom loadbalancing policies (= a plugin that provides the loadbalancing logic).
- https://github.com/grpc/grpc/blob/master/doc/load-balancing.md
- https://github.com/grpc/grpc/blob/master/doc/naming.md
- https://github.com/grpc/proposal/blob/master/A5-grpclb-in-dns.md
- https://github.com/grpc/proposal/blob/master/A24-lb-policy-config.md
### Transport support
Both implementations fully support gRPC over HTTP/2 in both TLS and plaintext.
Grpc.Core gets support for other transports supported by C-Core for free. Some (minor) integration work might be required to actually use these transports with gRPC C#.
grpc-dotnet supports other transports in .NET 5 or later. For example, grpc-dotnet [supports interprocess communication (IPC)](https://learn.microsoft.com/aspnet/core/grpc/interprocess) using named pipes and Unix domain sockets.
grpc-dotnet only supports the default transport.
Notes:
- Grpc.Core allows connections over UDS socket (both server and client) on Unix systems. It doesn't support named pipes on windows.
- Grpc.Core supports additional "transports" like ALTS and cfstream thanks to being build on top of C-core.
- Grpc.Core could provide an inprocess transport support but currently this functionality is not exposed in C# API.
- grpc-dotnet support for TLS is platform dependent. TLS is fully supported on Windows and Linux. There is limited support for servers hosted on MacOS prior to .NET 8.
- grpc-dotnet support for TLS is platform dependent. TLS is fully supported on Windows and Linux, but doesn't work on MacOS.
- grpc-dotnet support UDS socket on the server-side (On Unix systems, but also on [Windows](https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/))
### Retries / Request Hedging
Grpc.Core: implementation in C-core in progress, but no ETA yet
grpc-dotnet: Retries and hedging are fully supported.
grpc-dotnet: not implemented
Also see:
- https://learn.microsoft.com/aspnet/core/grpc/retries
- https://github.com/grpc/proposal/blob/master/A6-client-retries.md
https://github.com/grpc/proposal/blob/master/A6-client-retries.md,
### Channelz
@ -133,7 +112,7 @@ https://github.com/grpc/grpc/blob/master/doc/binary-logging.md
Grpc.Core: supported (algorithms: `gzip`, `deflate`)
grpc-dotnet: supported (algorithms: `gzip`, `deflate`), also provides public API to provide custom compression algorithm.
grpc-dotnet: supported (algorithms: `gzip`), also provides public API to provide custom compression algorithm.
Performance implications of using compression in both implementations haven't been measured. Compression functionality is offered mostly to comply with the spec.
@ -144,7 +123,7 @@ https://github.com/grpc/grpc/blob/master/doc/compression_cookbook.md
Grpc.Core: supported (exposed publicly on Channel), provided by C-Core
grpc-dotnet: Supported on .NET 5 or later
grpc-dotnet: not supported (to provide support, changes to .NET HttpClient are needed, so adding support is non-trivial).
https://github.com/grpc/grpc/blob/master/doc/connectivity-semantics-and-api.md
@ -168,7 +147,7 @@ https://github.com/grpc/grpc/blob/master/doc/keepalive.md
Grpc.Core: supported, provided by C-core
grpc-dotnet: Supported on .NET 5 or later
grpc-dotnet: not supported (implementing the wait_for_ready flag requires supporting channel connectivity first).
https://github.com/grpc/grpc/blob/master/doc/wait-for-ready.md
@ -176,7 +155,7 @@ https://github.com/grpc/grpc/blob/master/doc/wait-for-ready.md
Grpc.Core: conforms with the spec thanks to the C-core dependency. It is currently not possible to provide custom C# resolvers via resolver API (the APIs are in C core and aren't exposed in the C# layer).
grpc-dotnet: Resolving is fully supported on .NET 5 or later. grpc-dotnet also provides an [API to write custom resolvers](https://learn.microsoft.com/aspnet/core/grpc/loadbalancingwrite-custom-resolvers-and-load-balancers).
grpc-dotnet: only resolves basic DNS names. No API to provide a custom resolver.
https://github.com/grpc/grpc/blob/master/doc/naming.md
@ -186,7 +165,7 @@ grpc-dotnet allows port-sharing: serving both gRPC and non-gRPC traffic by the s
## Add-on Features
Features that don't necessarily require changes to the implementation's internals. They usually come as a separate opt-in nuget package.
Features that don't necessarily require changes to implementation's internals. They usually come as a separate opt-in nuget package.
### Addon: Server Reflection
Grpc.Core: supported via Grpc.Reflection nuget package
@ -218,22 +197,4 @@ grpc-dotnet supports integration with `HttpClientFactory` via the Grpc.Net.Clien
- Reuse of channel instances.
- Automatic propagation of cancellation and deadline when used in a `Grpc.AspNetCore` hosted gRPC service.
### Addon: gRPC JSON transcoding
grpc-dotnet supports providing a RESTful JSON API using [gRPC JSON transcoding](https://learn.microsoft.com/aspnet/core/grpc/json-transcoding).
gRPC JSON transcoding is an extension for ASP.NET Core that creates RESTful JSON APIs for gRPC services. Once configured, transcoding allows apps to call gRPC services with familiar HTTP concepts:
- HTTP verbs
- URL parameter binding
- JSON requests/responses
gRPC can still be used to call services.
### Addon: gRPC-Web
grpc-dotnet supports the [gRPC-Web protocol](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md).
gRPC-Web allows browser JavaScript and Blazor apps to call gRPC services. It's not possible to call a gRPC service over HTTP/2 from a browser-based app. gRPC services hosted in ASP.NET Core can be configured to support gRPC-Web alongside gRPC over HTTP/2.
https://learn.microsoft.com/aspnet/core/grpc/grpcweb
https://docs.microsoft.com/en-us/aspnet/core/grpc/clientfactory

View File

@ -10,9 +10,8 @@ release that the new release depends on.
## Releasing a new version of grpc-dotnet (every 6 weeks)
- Before cutting the release branch
- If needed, on the master branch update the `Grpc.Tools` and `Grpc.Core` dependency versions in [Directory.Packages.props](https://github.com/grpc/grpc-dotnet/blob/master/Directory.Packages.props)
to the latest pre-release of `Grpc.Tools` or `Grpc.Core` (that was released as part of the grpc/grpc release process)
- If needed, on the master branch update the `<GrpcPackageVersion>` dependency version in [dependencies.props](https://github.com/grpc/grpc-dotnet/blob/master/build/dependencies.props)
to the latest pre-release of `Grpc.Core.Api` (that was just released as part of the grpc/grpc release process)
- Make sure that any patches/bugfixes from the last released branch have been applied to the master branch as well.
- Cut the release branch from master branch (the branch format is `v2.25.x`, `v2.26.x`, ...).
@ -20,27 +19,22 @@ release that the new release depends on.
- On the release branch, replace the `-dev` suffix by `-pre1` under `<GrpcDotnetVersion>` version release number in [version.props](https://github.com/grpc/grpc-dotnet/blob/master/build/version.props)
to prepare for building the pre-release nugets.
- You'll also need to update `CurrentVersion` field in `Grpc.Core.Api`'s [VersionInfo.cs](https://github.com/grpc/grpc-dotnet/blob/6bbbf3627797ad8f787eced10b0e548cfd9ece15/src/Grpc.Core.Api/VersionInfo.cs#L44) to match the version number (otherwise tests will fail).
- Also check that the minor version number matches the branch name.
Also check that the minor version number matches the branch name.
- Build the signed nuget packages and push them to nuget.org (internal process). **These are the pre-release packages.**
- Create a new release and tag in https://github.com/grpc/grpc-dotnet/releases (by creating the tag from the current release branch).
Mark the release as "pre-release" in the github UI. Fill in the release notes.
- Wait for the stable release of `Grpc.Tools` from the `grpc/grpc` repository (as scheduled by the release schedule), keep checking the issue tracker for problems with the new grpc-dotnet pre-release packages.
- Wait for the stable release of `Grpc.Core.Api` (as scheduled by the release schedule), keep checking the issue tracker for problems with the new grpc-dotnet pre-release packages.
If problems are discovered and they need to be fixed, the release manager might choose to release more pre-releases (`-pre2`, `-pre3`, ...) before deciding to release as stable.
- **Make sure at least 7 days have elapsed since the last pre-release before proceeding with the stable release**, to give users enough time to test the prerelease nugets and discover potential issues. This is to decrease the likelyhood of pushing a bad stable release.
- Once stable version of `Grpc.Tools` is pushed, remove `-pre1` suffix of the `<GrpcDotnetVersion>` version release number in [version.props](https://github.com/grpc/grpc-dotnet/blob/master/build/version.props) to prepare for the stable release.
- Update `CurrentVersion` field in `Grpc.Core.Api`'s [VersionInfo.cs](https://github.com/grpc/grpc-dotnet/blob/6bbbf3627797ad8f787eced10b0e548cfd9ece15/src/Grpc.Core.Api/VersionInfo.cs#L44) to match the version number (otherwise tests will fail).
- Once stable version of `Grpc.Core.Api` is pushed, remove `-pre1` suffix of the `<GrpcDotnetVersion>` version release number in [version.props](https://github.com/grpc/grpc-dotnet/blob/master/build/version.props) to prepare for the stable release.
- Build the signed nuget packages and push them to nuget.org (internal process). **These are the stable grpc-dotnet packages.**
- Create a new release and tag in https://github.com/grpc/grpc-dotnet/releases (by creating the tag from the current release branch).
This is the stable release. Fill in the release notes and list changes since the previous _stable_ version.
This is the stable release. Fill in the release notes.
### After the release

View File

@ -1,15 +0,0 @@
services:
grpcweb-server:
build:
context: ./
dockerfile: ./testassets/InteropTestsWebsite/Dockerfile
image: grpc-dotnet/grpcweb-server
ports:
- "8080:80"
grpcweb-client:
build:
context: ./
dockerfile: ./testassets/InteropTestsGrpcWebWebsite/Dockerfile
image: grpc-dotnet/grpcweb-client
ports:
- "8081:80"

View File

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29230.61
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "Server\Server.csproj", "{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "Client\Client.csproj", "{48A1D3BC-A14B-436A-8822-6DE2BEF8B747}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}.Release|Any CPU.Build.0 = Release|Any CPU
{48A1D3BC-A14B-436A-8822-6DE2BEF8B747}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{48A1D3BC-A14B-436A-8822-6DE2BEF8B747}.Debug|Any CPU.Build.0 = Debug|Any CPU
{48A1D3BC-A14B-436A-8822-6DE2BEF8B747}.Release|Any CPU.ActiveCfg = Release|Any CPU
{48A1D3BC-A14B-436A-8822-6DE2BEF8B747}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D22B3129-3BFB-41FA-9FCE-E45EBEF8C2DD}
EndGlobalSection
EndGlobal

View File

@ -1,4 +0,0 @@
<Solution>
<Project Path="Client/Client.csproj" />
<Project Path="Server/Server.csproj" />
</Solution>

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
@ -10,9 +10,9 @@
<Protobuf Include="..\Proto\greet.proto" GrpcServices="None" Link="Protos\greet.proto"/>
<Protobuf Include="..\Proto\count.proto" GrpcServices="None" Link="Protos\count.proto"/>
<PackageReference Include="Google.Protobuf" />
<PackageReference Include="Grpc.Net.Client" />
<PackageReference Include="Grpc.Tools" PrivateAssets="All" />
<PackageReference Include="Google.Protobuf" Version="$(GoogleProtobufPackageVersion)" />
<PackageReference Include="Grpc.Net.Client" Version="$(GrpcDotNetPackageVersion)" />
<PackageReference Include="Grpc.Tools" Version="$(GrpcPackageVersion)" PrivateAssets="All" />
</ItemGroup>
</Project>

View File

@ -16,54 +16,72 @@
#endregion
using System;
using System.Threading;
using System.Threading.Tasks;
using Aggregate;
using Count;
using Greet;
using Grpc.Core;
using Grpc.Net.Client;
using var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new Aggregator.AggregatorClient(channel);
await ServerStreamingCallExample(client);
await ClientStreamingCallExample(client);
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
static async Task ServerStreamingCallExample(Aggregator.AggregatorClient client)
namespace Client
{
var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(3.5));
using var call = client.SayHellos(new HelloRequest { Name = "AggregatorClient" }, cancellationToken: cts.Token);
try
public class Program
{
await foreach (var message in call.ResponseStream.ReadAllAsync())
static Random RNG = new Random();
static async Task Main(string[] args)
{
Console.WriteLine("Greeting: " + message.Message);
var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new Aggregator.AggregatorClient(channel);
await ServerStreamingCallExample(client);
await ClientStreamingCallExample(client);
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
private static async Task ServerStreamingCallExample(Aggregator.AggregatorClient client)
{
var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(3.5));
using (var replies = client.SayHellos(new HelloRequest { Name = "AggregatorClient" }, cancellationToken: cts.Token))
{
try
{
await foreach (var message in replies.ResponseStream.ReadAllAsync())
{
Console.WriteLine("Greeting: " + message.Message);
}
}
catch (RpcException ex) when (ex.StatusCode == StatusCode.Cancelled)
{
Console.WriteLine("Stream cancelled.");
}
}
}
private static async Task ClientStreamingCallExample(Aggregator.AggregatorClient client)
{
using (var call = client.AccumulateCount())
{
for (var i = 0; i < 3; i++)
{
var count = RNG.Next(5);
Console.WriteLine($"Accumulating with {count}");
await call.RequestStream.WriteAsync(new CounterRequest { Count = count });
await Task.Delay(2000);
}
await call.RequestStream.CompleteAsync();
var response = await call;
Console.WriteLine($"Count: {response.Count}");
}
}
}
catch (RpcException ex) when (ex.StatusCode == StatusCode.Cancelled)
{
Console.WriteLine("Stream cancelled.");
}
}
static async Task ClientStreamingCallExample(Aggregator.AggregatorClient client)
{
using var call = client.AccumulateCount();
for (var i = 0; i < 3; i++)
{
var count = Random.Shared.Next(5);
Console.WriteLine($"Accumulating with {count}");
await call.RequestStream.WriteAsync(new CounterRequest { Count = count });
await Task.Delay(2000);
}
await call.RequestStream.CompleteAsync();
var response = await call;
Console.WriteLine($"Count: {response.Count}");
}

View File

@ -16,59 +16,23 @@
#endregion
using Count;
using Greet;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using Server;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc();
builder.Services.AddSingleton<IncrementingCounter>();
if (bool.TryParse(builder.Configuration["EnableOpenTelemetry"], out var enableOpenTelemetry) && enableOpenTelemetry)
namespace Server
{
builder.Services.AddOpenTelemetry()
.WithTracing(tracing =>
{
tracing.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("aggregator"));
if (builder.Environment.IsDevelopment())
{
// We want to view all traces in development
tracing.SetSampler(new AlwaysOnSampler());
}
tracing.AddAspNetCoreInstrumentation()
.AddGrpcClientInstrumentation()
.AddHttpClientInstrumentation();
tracing.AddZipkinExporter();
});
}
// These clients will call back to the server
builder.Services
.AddGrpcClient<Greeter.GreeterClient>((s, o) => { o.Address = GetCurrentAddress(s); })
.EnableCallContextPropagation();
builder.Services
.AddGrpcClient<Counter.CounterClient>((s, o) => { o.Address = GetCurrentAddress(s); })
.EnableCallContextPropagation();
var app = builder.Build();
app.MapGrpcService<GreeterService>();
app.MapGrpcService<CounterService>();
app.MapGrpcService<AggregatorService>();
app.Run();
static Uri GetCurrentAddress(IServiceProvider serviceProvider)
{
// Get the address of the current server from the request
var context = serviceProvider.GetRequiredService<IHttpContextAccessor>()?.HttpContext;
if (context == null)
public class Program
{
throw new InvalidOperationException("Could not get HttpContext.");
}
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
return new Uri($"{context.Request.Scheme}://{context.Request.Host.Value}");
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
@ -9,13 +9,12 @@
<Protobuf Include="..\Proto\greet.proto" GrpcServices="Both" Link="Protos\greet.proto" />
<Protobuf Include="..\Proto\count.proto" GrpcServices="Both" Link="Protos\count.proto" />
<PackageReference Include="Grpc.AspNetCore" />
<PackageReference Include="Grpc.AspNetCore" Version="$(GrpcDotNetPackageVersion)" />
<PackageReference Include="OpenTelemetry.Exporter.Zipkin" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" />
<PackageReference Include="OpenTelemetry.Instrumentation.GrpcNetClient" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" />
<PackageReference Include="OpenTelemetry.Hosting" Version="$(OpenTelemetryPackageVersion)" />
<PackageReference Include="OpenTelemetry.Exporter.Zipkin" Version="$(OpenTelemetryPackageVersion)" />
<PackageReference Include="OpenTelemetry.Collector.Dependencies" Version="$(OpenTelemetryPackageVersion)" />
<PackageReference Include="OpenTelemetry.Collector.AspNetCore" Version="$(OpenTelemetryPackageVersion)" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,97 @@
#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;
using System.Diagnostics;
using Count;
using Greet;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using OpenTelemetry.Trace.Configuration;
namespace Server
{
public partial class Startup
{
private readonly IConfiguration _configuration;
private const string EnableOpenTelemetryKey = "EnableOpenTelemetry";
public Startup(IConfiguration configuration)
{
_configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddGrpc();
services.AddSingleton<IncrementingCounter>();
if (_configuration.GetValue<bool>(EnableOpenTelemetryKey))
{
services.AddOpenTelemetry(telemetry =>
{
telemetry.UseZipkin(o => o.ServiceName = "aggregator");
telemetry.AddDependencyCollector();
telemetry.AddRequestCollector();
});
}
// These clients will call back to the server
services
.AddGrpcClient<Greeter.GreeterClient>((s, o) => { o.Address = GetCurrentAddress(s); })
.EnableCallContextPropagation();
services
.AddGrpcClient<Counter.CounterClient>((s, o) => { o.Address = GetCurrentAddress(s); })
.EnableCallContextPropagation();
static Uri GetCurrentAddress(IServiceProvider serviceProvider)
{
// Get the address of the current server from the request
var context = serviceProvider.GetRequiredService<IHttpContextAccessor>()?.HttpContext;
if (context == null)
{
throw new InvalidOperationException("Could not get HttpContext.");
}
return new Uri($"{context.Request.Scheme}://{context.Request.Host.Value}");
}
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<GreeterService>();
endpoints.MapGrpcService<CounterService>();
endpoints.MapGrpcService<AggregatorService>();
});
}
}
}

View File

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29521.150
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "Client\Client.csproj", "{B22D0F2E-D67A-413E-9450-4B64A60B56EF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "Server\Server.csproj", "{09CAF21C-D7D8-478C-9E74-3678DF615B8F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B22D0F2E-D67A-413E-9450-4B64A60B56EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B22D0F2E-D67A-413E-9450-4B64A60B56EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B22D0F2E-D67A-413E-9450-4B64A60B56EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B22D0F2E-D67A-413E-9450-4B64A60B56EF}.Release|Any CPU.Build.0 = Release|Any CPU
{09CAF21C-D7D8-478C-9E74-3678DF615B8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{09CAF21C-D7D8-478C-9E74-3678DF615B8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{09CAF21C-D7D8-478C-9E74-3678DF615B8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{09CAF21C-D7D8-478C-9E74-3678DF615B8F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {95736335-0C8B-4FDA-8722-E08046339B83}
EndGlobalSection
EndGlobal

View File

@ -1,4 +0,0 @@
<Solution>
<Project Path="Client/Client.csproj" />
<Project Path="Server/Server.csproj" />
</Solution>

View File

@ -1,17 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<TargetFramework>netstandard2.1</TargetFramework>
<RazorLangVersion>3.0</RazorLangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.Blazor" Version="$(MicrosoftAspNetCoreBlazorPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Blazor.Build" Version="$(MicrosoftAspNetCoreBlazorPackageVersion)" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.Blazor.HttpClient" Version="$(MicrosoftAspNetCoreBlazorPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Blazor.DevServer" Version="$(MicrosoftAspNetCoreBlazorPackageVersion)" PrivateAssets="all" />
<PackageReference Include="Google.Protobuf" />
<PackageReference Include="Grpc.Tools" PrivateAssets="All" />
<PackageReference Include="Grpc.Net.Client" />
<PackageReference Include="Grpc.Net.Client.Web" />
<PackageReference Include="Google.Protobuf" Version="$(GoogleProtobufPackageVersion)" />
<PackageReference Include="Grpc.Tools" Version="$(GrpcPackageVersion)" PrivateAssets="All" />
<PackageReference Include="Grpc.Net.Client" Version="$(GrpcDotNetPackageVersion)" />
<PackageReference Include="Grpc.Net.Client.Web" Version="$(GrpcDotNetPackageVersion)" />
<Protobuf Include="..\Proto\weather.proto" GrpcServices="Client" Link="Protos\weather.proto" Access="Internal" />
<Protobuf Include="..\Proto\count.proto" GrpcServices="Client" Link="Protos\count.proto" Access="Internal" />

View File

@ -1,5 +1,6 @@
@page "/counter"
@inject GrpcChannel Channel
@using Google.Protobuf.WellKnownTypes
@using Grpc.Core
<h1>Counter</h1>
@ -25,7 +26,7 @@
cts = new CancellationTokenSource();
var client = new Count.Counter.CounterClient(Channel);
using var call = client.StartCounter(new CounterRequest() { Start = currentCount }, cancellationToken: cts.Token);
var call = client.StartCounter(new Empty(), cancellationToken: cts.Token);
try
{

View File

@ -20,10 +20,9 @@ using System.Net.Http;
using System.Threading.Tasks;
using Grpc.Net.Client;
using Grpc.Net.Client.Web;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.AspNetCore.Blazor.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Weather;
namespace Client
{
@ -32,28 +31,25 @@ namespace Client
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<App>("app");
// Blazor WA currently has an issue related to server streaming. No messages are returned from the server until the call is complete.
// Setting WasmHttpMessageHandler.StreamingEnabled to true (reflection required) allows server streaming to work - https://github.com/mono/mono/issues/18718
var wasmHttpMessageHandlerType = System.Reflection.Assembly.Load("WebAssembly.Net.Http").GetType("WebAssembly.Net.Http.HttpClient.WasmHttpMessageHandler");
var streamingProperty = wasmHttpMessageHandlerType.GetProperty("StreamingEnabled", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
streamingProperty.SetValue(null, true, null);
builder.Services.AddSingleton(services =>
{
// Get the service address from appsettings.json
var config = services.GetRequiredService<IConfiguration>();
var backendUrl = config["BackendUrl"];
// If no address is set then fallback to the current webpage URL
if (string.IsNullOrEmpty(backendUrl))
{
var navigationManager = services.GetRequiredService<NavigationManager>();
backendUrl = navigationManager.BaseUri;
}
// Create a channel with a GrpcWebHandler that is addressed to the backend server.
// Create a gRPC-Web channel pointing to the backend server.
//
// GrpcWebText is used because server streaming requires it. If server streaming is not used in your app
// then GrpcWeb is recommended because it produces smaller messages.
var httpHandler = new GrpcWebHandler(GrpcWebMode.GrpcWebText, new HttpClientHandler());
var httpClient = new HttpClient(new GrpcWebHandler(GrpcWebMode.GrpcWebText, new HttpClientHandler()));
return GrpcChannel.ForAddress(backendUrl, new GrpcChannelOptions { HttpHandler = httpHandler });
var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions { HttpClient = httpClient });
return channel;
});
await builder.Build().RunAsync();

View File

@ -1,4 +0,0 @@
{
// Explicit backend URL (override current site)
"BackendUrl": null
}

View File

@ -14,7 +14,7 @@ a, .btn-link {
border-color: #1861ac;
}
#app {
app {
position: relative;
display: flex;
flex-direction: column;
@ -151,7 +151,7 @@ a, .btn-link {
}
@media (min-width: 768px) {
#app {
app {
flex-direction: row;
}

View File

@ -11,7 +11,7 @@
</head>
<body>
<div id="app">Loading...</div>
<app>Loading...</app>
<div id="blazor-error-ui">
An unhandled error has occurred.

View File

@ -14,14 +14,12 @@
syntax = "proto3";
import "google/protobuf/empty.proto";
package count;
service Counter {
rpc StartCounter (CounterRequest) returns (stream CounterResponse);
}
message CounterRequest {
int32 start = 1;
rpc StartCounter (google.protobuf.Empty) returns (stream CounterResponse);
}
message CounterResponse {

View File

@ -16,38 +16,23 @@
#endregion
using Microsoft.AspNetCore.ResponseCompression;
using Server.Services;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc();
builder.Services.AddResponseCompression(opts =>
namespace Server
{
opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
new[] { "application/octet-stream" });
});
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
var app = builder.Build();
app.UseResponseCompression();
if (app.Environment.IsDevelopment())
{
app.UseWebAssemblyDebugging();
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
else
{
app.UseHsts();
}
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseGrpcWeb();
app.MapGrpcService<WeatherService>().EnableGrpcWeb();
app.MapGrpcService<CounterService>().EnableGrpcWeb();
app.MapFallbackToFile("index.html");
app.Run();

View File

@ -1,29 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:59193/",
"sslPort": 44375
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Server": {
"commandName": "Project",
"launchBrowser": true,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:5001;http://localhost:5000"
}
}
}

View File

@ -1,17 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<UserSecretsId>46982f83-f153-443e-b589-4b2bc7b5945e</UserSecretsId>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Protobuf Include="..\Proto\weather.proto" GrpcServices="Server" Link="Protos\weather.proto" />
<Protobuf Include="..\Proto\count.proto" GrpcServices="Server" Link="Protos\count.proto" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" />
<PackageReference Include="Grpc.AspNetCore" />
<PackageReference Include="Grpc.AspNetCore.Web" />
<PackageReference Include="Microsoft.AspNetCore.Blazor.Server" Version="$(MicrosoftAspNetCoreBlazorPackageVersion)" />
<PackageReference Include="Grpc.AspNetCore" Version="$(GrpcDotNetPackageVersion)" />
<PackageReference Include="Grpc.AspNetCore.Web" Version="$(GrpcDotNetPackageVersion)" />
</ItemGroup>
<ItemGroup>

View File

@ -19,16 +19,19 @@
using System;
using System.Threading.Tasks;
using Count;
using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
namespace Server.Services
{
public class CounterService : Counter.CounterBase
{
public override async Task StartCounter(CounterRequest request, IServerStreamWriter<CounterResponse> responseStream, ServerCallContext context)
public override async Task StartCounter(Empty request, IServerStreamWriter<CounterResponse> responseStream, ServerCallContext context)
{
var count = request.Start;
var count = 0;
// Attempt to run until canceled by the client
// Blazor WA is unable to cancel a call that has started - https://github.com/mono/mono/issues/18717
while (!context.CancellationToken.IsCancellationRequested)
{
await responseStream.WriteAsync(new CounterResponse

View File

@ -0,0 +1,69 @@
#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.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Server.Services;
namespace Server
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddGrpc();
services.AddResponseCompression(opts =>
{
opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
new[] { "application/octet-stream" });
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseResponseCompression();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBlazorDebugging();
}
app.UseStaticFiles();
app.UseClientSideBlazorFiles<Client.Program>();
app.UseRouting();
app.UseGrpcWeb();
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<WeatherService>().EnableGrpcWeb();
endpoints.MapGrpcService<CounterService>().EnableGrpcWeb();
endpoints.MapFallbackToClientSideBlazor<Client.Program>("index.html");
});
}
}
}

View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29230.61
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "Server\Server.csproj", "{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D22B3129-3BFB-41FA-9FCE-E45EBEF8C2DD}
EndGlobalSection
EndGlobal

View File

@ -1,3 +0,0 @@
<Solution>
<Project Path="Server/Server.csproj" />
</Solution>

View File

@ -16,24 +16,23 @@
#endregion
using Server.Services;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
namespace Server
{
app.UseHsts();
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
app.UseHttpsRedirection();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseGrpcWeb();
app.MapGrpcService<GreeterService>().EnableGrpcWeb();
app.Run();

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
<SpaRoot>wwwroot\</SpaRoot>
<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**;$(SpaRoot)dist\**</DefaultItemExcludes>
</PropertyGroup>
@ -9,8 +9,8 @@
<ItemGroup>
<Protobuf Include="..\Proto\greet.proto" GrpcServices="Server" Link="Protos\greet.proto" />
<PackageReference Include="Grpc.AspNetCore" />
<PackageReference Include="Grpc.AspNetCore.Web" />
<PackageReference Include="Grpc.AspNetCore" Version="$(GrpcDotNetPackageVersion)" />
<PackageReference Include="Grpc.AspNetCore.Web" Version="$(GrpcDotNetPackageVersion)" />
</ItemGroup>
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">

View File

@ -0,0 +1,59 @@
#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 Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Server.Services;
namespace Server
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddGrpc();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseGrpcWeb();
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<GreeterService>().EnableGrpcWeb();
});
}
}
}

View File

@ -4,5 +4,10 @@
"Default": "Information"
}
},
"AllowedHosts": "*"
"AllowedHosts": "*",
"Kestrel": {
"EndpointDefaults": {
"Protocols": "Http2"
}
}
}

View File

@ -10,7 +10,7 @@ var resultText = document.getElementById('result');
var streamingCall = null;
// Unary call
sendInput.onclick = function () {
sendInput.onclick =function () {
var request = new HelloRequest();
request.setName(nameInput.value);
@ -30,15 +30,10 @@ streamInput.onclick = function () {
request.setName(nameInput.value);
streamingCall = client.sayHellos(request, {});
streamingCall.on('data', (response) => {
streamingCall.on('data', function (response) {
resultText.innerHTML += htmlEscape(response.getMessage()) + '<br />';
});
streamingCall.on('status', (status) => {
if (status.code == 0) {
resultText.innerHTML += 'Done';
} else {
resultText.innerHTML += 'Error: ' + htmlEscape(status.details);
}
streamingCall.on('end', function () {
});
} else {
streamingCall.cancel();

File diff suppressed because it is too large Load Diff

View File

@ -5,8 +5,9 @@
"devDependencies": {
"@grpc/proto-loader": "^0.3.0",
"google-protobuf": "^3.6.1",
"grpc": "^1.15.0",
"grpc-web": "^1.0.0",
"webpack": "^5.94.0",
"webpack-cli": "^5.0.1"
"webpack": "^4.16.5",
"webpack-cli": "^3.1.0"
}
}

View File

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29230.61
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Server\Server.csproj", "{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "Client\Client.csproj", "{48A1D3BC-A14B-436A-8822-6DE2BEF8B747}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}.Release|Any CPU.Build.0 = Release|Any CPU
{48A1D3BC-A14B-436A-8822-6DE2BEF8B747}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{48A1D3BC-A14B-436A-8822-6DE2BEF8B747}.Debug|Any CPU.Build.0 = Debug|Any CPU
{48A1D3BC-A14B-436A-8822-6DE2BEF8B747}.Release|Any CPU.ActiveCfg = Release|Any CPU
{48A1D3BC-A14B-436A-8822-6DE2BEF8B747}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D22B3129-3BFB-41FA-9FCE-E45EBEF8C2DD}
EndGlobalSection
EndGlobal

View File

@ -1,4 +0,0 @@
<Solution>
<Project Path="Client/Client.csproj" />
<Project Path="Server/Server.csproj" />
</Solution>

View File

@ -2,15 +2,15 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Protobuf Include="..\Proto\certify.proto" GrpcServices="Client" Link="Protos\certify.proto" />
<PackageReference Include="Google.Protobuf" />
<PackageReference Include="Grpc.Net.Client" />
<PackageReference Include="Grpc.Tools" PrivateAssets="All" />
<PackageReference Include="Google.Protobuf" Version="$(GoogleProtobufPackageVersion)" />
<PackageReference Include="Grpc.Net.Client" Version="$(GrpcDotNetPackageVersion)" />
<PackageReference Include="Grpc.Tools" Version="$(GrpcPackageVersion)" PrivateAssets="All" />
<None Update="Certs\client.pfx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>

View File

@ -16,66 +16,79 @@
#endregion
using System;
using System.IO;
using System.Net.Http;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Certify;
using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
using Grpc.Net.Client;
// The server will return 403 (Forbidden). The method requires a certificate
await CallCertificateInfo(includeClientCertificate: false);
// The server will return a successful gRPC response
await CallCertificateInfo(includeClientCertificate: true);
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
static async Task CallCertificateInfo(bool includeClientCertificate)
namespace Client
{
try
public class Program
{
Console.WriteLine($"Setting up HttpClient. Client has certificate: {includeClientCertificate}");
using var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions
static async Task Main(string[] args)
{
HttpHandler = CreateHttpHandler(includeClientCertificate)
});
var client = new Certifier.CertifierClient(channel);
// The server will return 403 (Forbidden). The method requires a certificate
await CallCertificateInfo(includeClientCertificate: false);
Console.WriteLine("Sending gRPC call...");
var certificateInfo = await client.GetCertificateInfoAsync(new Empty());
// The server will return a successful gRPC response
await CallCertificateInfo(includeClientCertificate: true);
Console.WriteLine($"Server received client certificate: {certificateInfo.HasCertificate}");
if (certificateInfo.HasCertificate)
{
Console.WriteLine($"Client certificate name: {certificateInfo.Name}");
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
}
catch (RpcException ex)
{
Console.WriteLine($"gRPC error from calling service: {ex.Status.Detail}");
}
catch
{
Console.WriteLine($"Unexpected error calling service.");
throw;
}
Console.WriteLine();
}
static HttpClientHandler CreateHttpHandler(bool includeClientCertificate)
{
var handler = new HttpClientHandler();
if (includeClientCertificate)
{
// Load client certificate
var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);
var certPath = Path.Combine(basePath!, "Certs", "client.pfx");
var clientCertificate = X509CertificateLoader.LoadPkcs12FromFile(certPath, "1111");
handler.ClientCertificates.Add(clientCertificate);
}
return handler;
private static async Task CallCertificateInfo(bool includeClientCertificate)
{
try
{
Console.WriteLine($"Setting up HttpClient. Client has certificate: {includeClientCertificate}");
var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions
{
HttpClient = CreateHttpClient(includeClientCertificate)
});
var client = new Certifier.CertifierClient(channel);
Console.WriteLine("Sending gRPC call...");
var certificateInfo = await client.GetCertificateInfoAsync(new Empty());
Console.WriteLine($"Server received client certificate: {certificateInfo.HasCertificate}");
if (certificateInfo.HasCertificate)
{
Console.WriteLine($"Client certificate name: {certificateInfo.Name}");
}
}
catch (RpcException ex)
{
Console.WriteLine($"gRPC error from calling service: {ex.Status.Detail}");
}
catch
{
Console.WriteLine($"Unexpected error calling service.");
throw;
}
}
private static HttpClient CreateHttpClient(bool includeClientCertificate)
{
var handler = new HttpClientHandler();
if (includeClientCertificate)
{
// Load client certificate
var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);
var certPath = Path.Combine(basePath!, "Certs", "client.pfx");
var clientCertificate = new X509Certificate2(certPath, "1111");
handler.ClientCertificates.Add(clientCertificate);
}
// Create client
return new HttpClient(handler);
}
}
}

View File

@ -16,36 +16,31 @@
#endregion
using System.Security.Cryptography.X509Certificates;
using Microsoft.AspNetCore.Authentication.Certificate;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Https;
using Server;
using Microsoft.Extensions.Hosting;
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(kestrelOptions =>
namespace Server
{
kestrelOptions.ConfigureHttpsDefaults(httpsOptions =>
public class Program
{
httpsOptions.ClientCertificateMode = ClientCertificateMode.AllowCertificate;
});
});
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
builder.Services.AddGrpc();
builder.Services.AddAuthorization();
builder.Services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(options =>
{
// Not recommended in production environments. The example is using a self-signed test certificate.
options.RevocationMode = X509RevocationMode.NoCheck;
options.ChainTrustValidationMode = X509ChainTrustMode.CustomRootTrust;
options.AllowedCertificateTypes = CertificateTypes.All;
});
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapGrpcService<CertifierService>();
app.Run();
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureKestrel(kestrelOptions =>
{
kestrelOptions.ConfigureHttpsDefaults(httpsOptions =>
{
httpsOptions.ClientCertificateMode = ClientCertificateMode.AllowCertificate;
});
});
webBuilder.UseStartup<Startup>();
});
}
}

View File

@ -1,14 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Protobuf Include="..\Proto\certify.proto" GrpcServices="Server" Link="Protos\certify.proto" />
<PackageReference Include="Grpc.AspNetCore" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Certificate" />
<PackageReference Include="Grpc.AspNetCore" Version="$(GrpcDotNetPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Certificate" Version="$(MicrosoftAspNetCorePackageVersion)" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,62 @@
#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.Security.Cryptography.X509Certificates;
using Microsoft.AspNetCore.Authentication.Certificate;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace Server
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddGrpc();
services.AddAuthorization();
services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(options =>
{
// Not recommended in production environments. The example is using a self-signed test certificate.
options.RevocationMode = X509RevocationMode.NoCheck;
options.AllowedCertificateTypes = CertificateTypes.All;
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<CertifierService>();
});
}
}
}

View File

@ -1,4 +0,0 @@
<Solution>
<Project Path="Client/Client.csproj" />
<Project Path="Server/Server.csproj" />
</Solution>

View File

@ -1,16 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Protobuf Include="..\Proto\data_channel.proto" GrpcServices="Client" Link="Protos\data_channel.proto" />
<PackageReference Include="Google.Protobuf" />
<PackageReference Include="Grpc.Net.Client" />
<PackageReference Include="Grpc.Tools" PrivateAssets="All" />
</ItemGroup>
</Project>

View File

@ -1,66 +0,0 @@
#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.Text;
using DataChannel;
using Google.Protobuf;
using Grpc.Core;
using Grpc.Net.Client;
using var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new DataChanneler.DataChannelerClient(channel);
await UploadDataAsync(client);
await DownloadResultsAsync(client);
Console.WriteLine("Shutting down");
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
static async Task UploadDataAsync(DataChanneler.DataChannelerClient client)
{
var call = client.UploadData();
var dataChunks = TestData.Chunk(5);
foreach (var chunk in dataChunks)
{
Console.WriteLine($"Uploading chunk: {chunk.Length} bytes");
await call.RequestStream.WriteAsync(new DataRequest { Value = ByteString.CopyFrom(chunk) });
}
await call.RequestStream.CompleteAsync();
var result = await call;
Console.WriteLine($"Total upload processed: {result.BytesProcessed} bytes");
}
static async Task DownloadResultsAsync(DataChanneler.DataChannelerClient client)
{
var call = client.DownloadResults(new DataRequest { Value = ByteString.CopyFrom(TestData) });
await foreach (var result in call.ResponseStream.ReadAllAsync())
{
Console.WriteLine($"Downloaded bytes processed result: {result.BytesProcessed}");
}
}
public partial class Program
{
private static readonly byte[] TestData = Encoding.UTF8.GetBytes("The quick brown fox jumped over the lazy dog.");
}

View File

@ -1,30 +0,0 @@
// 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.
syntax = "proto3";
package data_channel;
service DataChanneler {
rpc UploadData (stream DataRequest) returns (DataResult);
rpc DownloadResults (DataRequest) returns (stream DataResult);
}
message DataRequest {
bytes value = 1;
}
message DataResult {
int32 bytes_processed = 1;
}

View File

@ -1,27 +0,0 @@
#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 Server;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc();
var app = builder.Build();
app.MapGrpcService<DataChannelerService>();
app.Run();

View File

@ -1,12 +0,0 @@
{
"profiles": {
"Server": {
"commandName": "Project",
"launchBrowser": false,
"applicationUrl": "https://localhost:5001",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -1,13 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Protobuf Include="..\Proto\data_channel.proto" GrpcServices="Server" Link="Protos\data_channel.proto" />
<PackageReference Include="Grpc.AspNetCore" />
</ItemGroup>
</Project>

View File

@ -1,107 +0,0 @@
#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.Channels;
using DataChannel;
using Grpc.Core;
namespace Server
{
public class DataChannelerService : DataChanneler.DataChannelerBase
{
private readonly ILogger _logger;
public DataChannelerService(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<DataChannelerService>();
}
public override async Task<DataResult> UploadData(
IAsyncStreamReader<DataRequest> requestStream, ServerCallContext context)
{
var channel = Channel.CreateBounded<DataRequest>(new BoundedChannelOptions(capacity: 5)
{
SingleReader = false,
SingleWriter = true
});
var readTask = Task.Run(async () =>
{
await foreach (var message in requestStream.ReadAllAsync())
{
await channel.Writer.WriteAsync(message);
}
channel.Writer.Complete();
});
// Process incoming messages on three threads.
var bytesProcessedByThread = await Task.WhenAll(
ProcessMessagesAsync(channel.Reader, _logger),
ProcessMessagesAsync(channel.Reader, _logger),
ProcessMessagesAsync(channel.Reader, _logger));
await readTask;
return new DataResult { BytesProcessed = bytesProcessedByThread.Sum() };
static async Task<int> ProcessMessagesAsync(ChannelReader<DataRequest> reader, ILogger logger)
{
var total = 0;
await foreach (var message in reader.ReadAllAsync())
{
total += message.Value.Length;
}
return total;
}
}
public override async Task DownloadResults(DataRequest request,
IServerStreamWriter<DataResult> responseStream, ServerCallContext context)
{
var channel = Channel.CreateBounded<DataResult>(new BoundedChannelOptions(capacity: 5)
{
SingleReader = true,
SingleWriter = false
});
var consumerTask = Task.Run(async () =>
{
// Consume messages from channel and write to response stream.
await foreach (var message in channel.Reader.ReadAllAsync())
{
await responseStream.WriteAsync(message);
}
});
var dataChunks = request.Value.Chunk(size: 10);
// Write messages to channel from multiple threads.
await Task.WhenAll(dataChunks.Select(
async c =>
{
var message = new DataResult { BytesProcessed = c.Length };
await channel.Writer.WriteAsync(message);
}));
// Complete writing and wait for consumer to complete.
channel.Writer.Complete();
await consumerTask;
}
}
}

View File

@ -1,13 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Shared\Shared.csproj" />
<PackageReference Include="Grpc.Net.Client" />
</ItemGroup>
</Project>

View File

@ -1,31 +0,0 @@
#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 Grpc.Net.Client;
using ProtoBuf.Grpc.Client;
using Shared;
using var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = channel.CreateGrpcService<IGreeterService>();
var reply = await client.SayHelloAsync(new HelloRequest { Name = "GreeterClient" });
Console.WriteLine("Greeting: " + reply.Message);
Console.WriteLine("Shutting down");
Console.WriteLine("Press any key to exit...");
Console.ReadKey();

View File

@ -1,5 +0,0 @@
<Solution>
<Project Path="Client/Client.csproj" />
<Project Path="Server/Server.csproj" />
<Project Path="Shared/Shared.csproj" />
</Solution>

View File

@ -1,29 +0,0 @@
#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 ProtoBuf.Grpc.Server;
using Server;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc();
builder.Services.AddCodeFirstGrpc();
var app = builder.Build();
app.MapGrpcService<GreeterService>();
app.Run();

View File

@ -1,13 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Shared\Shared.csproj" />
<PackageReference Include="protobuf-net.Grpc.AspNetCore" />
</ItemGroup>
</Project>

View File

@ -1,41 +0,0 @@
#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.Tasks;
using Microsoft.Extensions.Logging;
using ProtoBuf.Grpc;
using Shared;
namespace Server
{
public class GreeterService : IGreeterService
{
private readonly ILogger _logger;
public GreeterService(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<GreeterService>();
}
public Task<HelloReply> SayHelloAsync(HelloRequest request, CallContext context = default)
{
_logger.LogInformation($"Sending hello to {request.Name}");
return Task.FromResult(new HelloReply { Message = "Hello " + request.Name });
}
}
}

View File

@ -1,10 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Grpc": "Information",
"Microsoft": "Information"
}
}
}

View File

@ -1,13 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information"
}
},
"AllowedHosts": "*",
"Kestrel": {
"EndpointDefaults": {
"Protocols": "Http2"
}
}
}

View File

@ -1,31 +0,0 @@
#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.ServiceModel;
using System.Threading.Tasks;
using ProtoBuf.Grpc;
namespace Shared
{
[ServiceContract]
public interface IGreeterService
{
[OperationContract]
Task<HelloReply> SayHelloAsync(HelloRequest request, CallContext context = default);
}
}

View File

@ -1,11 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="protobuf-net.Grpc" />
</ItemGroup>
</Project>

View File

@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Protobuf Include="..\Proto\greet.proto" GrpcServices="Client" Link="Protos\greet.proto" />
<PackageReference Include="Google.Protobuf" />
<PackageReference Include="Grpc.Net.Client" />
<PackageReference Include="Grpc.Tools" PrivateAssets="All" />
</ItemGroup>
</Project>

View File

@ -1,42 +0,0 @@
#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 Greet;
using Grpc.Core;
using Grpc.Net.Client;
using var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new Greeter.GreeterClient(channel);
await UnaryCallExample(client);
Console.WriteLine("Shutting down");
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
static async Task UnaryCallExample(Greeter.GreeterClient client)
{
// 'grpc-internal-encoding-request' is a special metadata value that tells
// the client to compress the request.
// This metadata is only used in the client is not sent as a header to the server.
var metadata = new Metadata();
metadata.Add("grpc-internal-encoding-request", "gzip");
var reply = await client.SayHelloAsync(new HelloRequest { Name = "GreeterClient" }, headers: metadata);
Console.WriteLine("Greeting: " + reply.Message);
}

View File

@ -1,4 +0,0 @@
<Solution>
<Project Path="Client/Client.csproj" />
<Project Path="Server/Server.csproj" />
</Solution>

View File

@ -1,30 +0,0 @@
#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 Server;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc(o =>
{
o.ResponseCompressionAlgorithm = "gzip";
});
var app = builder.Build();
app.MapGrpcService<GreeterService>();
app.Run();

View File

@ -1,12 +0,0 @@
{
"profiles": {
"Server": {
"commandName": "Project",
"launchBrowser": false,
"applicationUrl": "https://localhost:5001",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -1,10 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Grpc": "Information",
"Microsoft": "Information"
}
}
}

View File

@ -1,13 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information"
}
},
"AllowedHosts": "*",
"Kestrel": {
"EndpointDefaults": {
"Protocols": "Http2"
}
}
}

View File

@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Protobuf Include="..\Proto\weather.proto" GrpcServices="Server" Link="Protos\weather.proto" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" />
<PackageReference Include="Grpc.AspNetCore" />
<PackageReference Include="Grpc.AspNetCore.Web" />
</ItemGroup>
</Project>

View File

@ -1,14 +0,0 @@
FROM mcr.microsoft.com/dotnet/sdk:10.0-preview AS build-env
WORKDIR /app
# Copy everything
COPY . ./
RUN dotnet --info
RUN dotnet restore examples/Container/Backend
RUN dotnet publish examples/Container/Backend -c Release -o out
# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:10.0-preview
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "Backend.dll"]

View File

@ -1,28 +0,0 @@
#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 Server.Services;
var builder = WebApplication.CreateBuilder(args);
builder.Logging.SetMinimumLevel(LogLevel.Trace);
builder.Services.AddGrpc();
var app = builder.Build();
app.MapGrpcService<WeatherService>();
app.Run();

View File

@ -1,57 +0,0 @@
#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;
using System.Linq;
using System.Threading.Tasks;
using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
using Weather;
namespace Server.Services
{
public class WeatherService : WeatherForecasts.WeatherForecastsBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
public override async Task<GetWeatherForecastsResponse> GetWeatherForecasts(Empty request, ServerCallContext context)
{
var httpContext = context.GetHttpContext();
await context.WriteResponseHeadersAsync(new Metadata
{
{ "host", $"{httpContext.Request.Scheme}://{httpContext.Request.Host}" }
});
var rng = new Random();
var results = Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.UtcNow.AddDays(index).ToTimestamp(),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
}).ToArray();
var response = new GetWeatherForecastsResponse();
response.Forecasts.AddRange(results);
return response;
}
}
}

View File

@ -1,10 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Grpc": "Information",
"Microsoft": "Information"
}
}
}

View File

@ -1,13 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Trace"
}
},
"AllowedHosts": "*",
"Kestrel": {
"EndpointDefaults": {
"Protocols": "Http2"
}
}
}

View File

@ -1,4 +0,0 @@
<Solution>
<Project Path="Backend/Backend.csproj" />
<Project Path="Frontend/Frontend.csproj" />
</Solution>

View File

@ -1,10 +0,0 @@
<Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>

View File

@ -1,42 +0,0 @@
#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;
namespace Frontend.Balancer
{
public class BalancerConfiguration
{
public event EventHandler? Updated;
public LoadBalancerName LoadBalancerPolicyName { get; private set; } = LoadBalancerName.PickFirst;
public void Update(LoadBalancerName loadBalancerPolicyName)
{
LoadBalancerPolicyName = loadBalancerPolicyName;
Updated?.Invoke(this, EventArgs.Empty);
}
}
public enum LoadBalancerName
{
RoundRobin,
PickFirst
}
}

View File

@ -1,123 +0,0 @@
#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 Grpc.Core;
using Grpc.Net.Client.Balancer;
using Grpc.Net.Client.Configuration;
namespace Frontend.Balancer
{
public class ConfigurableResolverFactory : ResolverFactory
{
private static readonly BalancerAttributesKey<string> HostOverrideKey = new BalancerAttributesKey<string>("HostOverride");
private readonly ResolverFactory _innerResolverFactory;
private readonly BalancerConfiguration _balancerConfiguration;
public ConfigurableResolverFactory(ResolverFactory innerResolverFactory, BalancerConfiguration balancerConfiguration)
{
_innerResolverFactory = innerResolverFactory;
_balancerConfiguration = balancerConfiguration;
}
public override string Name => _innerResolverFactory.Name;
public override Resolver Create(ResolverOptions options)
{
return new ConfigurableResolver(_innerResolverFactory.Create(options), _balancerConfiguration);
}
private class ConfigurableResolver : Resolver
{
private readonly Resolver _innerResolver;
private readonly BalancerConfiguration _balancerConfiguration;
private ResolverResult? _lastResult;
private Action<ResolverResult>? _listener;
public ConfigurableResolver(Resolver innerResolver, BalancerConfiguration balancerConfiguration)
{
_innerResolver = innerResolver;
_balancerConfiguration = balancerConfiguration;
_balancerConfiguration.Updated += OnConfigurationUpdated;
}
public override void Start(Action<ResolverResult> listener)
{
_listener = listener;
_innerResolver.Start(result =>
{
_lastResult = result;
RaiseResult(result);
});
}
public override void Refresh()
{
_innerResolver.Refresh();
}
private void OnConfigurationUpdated(object? sender, EventArgs e)
{
// Can't just call RefreshAsync and get new results because of rate limiting.
if (_lastResult != null)
{
RaiseResult(_lastResult);
}
}
private void RaiseResult(ResolverResult result)
{
if (_listener != null)
{
if (result.Addresses != null)
{
var policyName = _balancerConfiguration.LoadBalancerPolicyName switch
{
LoadBalancerName.PickFirst => "pick_first",
LoadBalancerName.RoundRobin => "round_robin",
_ => throw new InvalidOperationException("Unexpected load balancer.")
};
var serviceConfig = new ServiceConfig
{
LoadBalancingConfigs = { new LoadBalancingConfig(policyName) }
};
// DNS results change order between refreshes.
// Explicitly order by host to keep result order consistent.
var orderedAddresses = result.Addresses.OrderBy(a => a.EndPoint.Host).ToList();
// Remove host override from addresses so the destination IP address is available.
// The sample does this because the server returns the IP address to the client.
// This makes it clear that gRPC calls are balanced between pods.
foreach (var address in orderedAddresses)
{
((IDictionary<string, object?>)address.Attributes).Remove(HostOverrideKey.Key);
}
_listener(ResolverResult.ForResult(orderedAddresses, serviceConfig, Status.DefaultSuccess));
}
else
{
_listener(ResolverResult.ForFailure(result.Status));
}
}
}
}
}
}

View File

@ -1,89 +0,0 @@
#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.Collections.Generic;
using Grpc.Core;
using Grpc.Net.Client.Balancer;
namespace Frontend.Balancer
{
public record ReportedSubchannelState(Subchannel Subchannel, ConnectivityState State);
public class ReportingChannelControlHelper : IChannelControlHelper
{
private readonly IChannelControlHelper _controller;
private readonly SubchannelReporter _subchannelReporter;
private readonly List<ReportedSubchannelState> _subchannels;
private ConnectivityState _state;
public ReportingChannelControlHelper(
IChannelControlHelper controller,
SubchannelReporter subchannelReporter)
{
_controller = controller;
_subchannels = new List<ReportedSubchannelState>();
_subchannelReporter = subchannelReporter;
}
public Subchannel CreateSubchannel(SubchannelOptions options)
{
var subchannel = _controller.CreateSubchannel(options);
subchannel.OnStateChanged(s => OnSubchannelStateChanged(subchannel, s));
_subchannels.Add(new ReportedSubchannelState(subchannel, ConnectivityState.Idle));
NotifySubscribers();
return subchannel;
}
private void OnSubchannelStateChanged(Subchannel subchannel, SubchannelState s)
{
var i = _subchannels.FindIndex(s => s.Subchannel == subchannel);
if (i >= 0)
{
if (s.State == ConnectivityState.Shutdown)
{
_subchannels.RemoveAt(i);
}
else
{
_subchannels[i] = new ReportedSubchannelState(subchannel, s.State);
}
}
}
public void UpdateState(BalancerState state)
{
_controller.UpdateState(state);
_state = state.ConnectivityState;
NotifySubscribers();
}
private void NotifySubscribers()
{
_subchannelReporter.NotifySubscribers(new SubchannelReporterResult(_state, _subchannels));
}
public void RefreshResolver()
{
_controller.RefreshResolver();
}
}
}

View File

@ -1,47 +0,0 @@
#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.Collections.Generic;
using Grpc.Net.Client.Balancer;
namespace Frontend.Balancer
{
public class ReportingLoadBalancerFactory : LoadBalancerFactory
{
private readonly LoadBalancerFactory _loadBalancerFactory;
private readonly SubchannelReporter _subchannelReporter;
public ReportingLoadBalancerFactory(LoadBalancerFactory loadBalancerFactory, SubchannelReporter subchannelReporter)
{
_loadBalancerFactory = loadBalancerFactory;
_subchannelReporter = subchannelReporter;
}
public override string Name => _loadBalancerFactory.Name;
public override LoadBalancer Create(LoadBalancerOptions options)
{
// Wrap the helper so that state updates can be intercepted.
// State information is then passed to the reporter.
var reportingController = new ReportingChannelControlHelper(options.Controller, _subchannelReporter);
options = new LoadBalancerOptions(reportingController, options.LoggerFactory, options.Configuration);
return _loadBalancerFactory.Create(options);
}
}
}

View File

@ -1,47 +0,0 @@
#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 Grpc.Net.Client.Balancer;
namespace Frontend.Balancer
{
public static class ReportingSetup
{
public static void RegisterReportingServices(IServiceCollection services)
{
// These services allow the load balancer policy to be configured and subchannels to be reported in the UI.
services.AddSingleton<SubchannelReporter>();
services.AddSingleton<BalancerConfiguration>();
services.AddSingleton<ResolverFactory>(s =>
{
var inner = new DnsResolverFactory(refreshInterval: TimeSpan.FromSeconds(20));
return new ConfigurableResolverFactory(inner, s.GetRequiredService<BalancerConfiguration>());
});
services.AddSingleton<LoadBalancerFactory>(s =>
{
var inner = new RoundRobinBalancerFactory();
return new ReportingLoadBalancerFactory(inner, s.GetRequiredService<SubchannelReporter>());
});
services.AddSingleton<LoadBalancerFactory>(s =>
{
var inner = new PickFirstBalancerFactory();
return new ReportingLoadBalancerFactory(inner, s.GetRequiredService<SubchannelReporter>());
});
}
}
}

View File

@ -1,94 +0,0 @@
#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;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using Grpc.Core;
using Grpc.Net.Client.Balancer;
namespace Frontend.Balancer
{
public class SubchannelReporter : IObservable<SubchannelReporterResult>
{
private readonly ObservableCollection<IObserver<SubchannelReporterResult>> _observers;
private SubchannelReporterResult _lastResult = new SubchannelReporterResult(ConnectivityState.Idle, new List<ReportedSubchannelState>());
public SubchannelReporter()
{
_observers = new ObservableCollection<IObserver<SubchannelReporterResult>>();
_observers.CollectionChanged += OnObserversChanged;
}
private void OnObserversChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
NotifySubscriptersCore();
}
public void NotifySubscribers(SubchannelReporterResult result)
{
_lastResult = result;
NotifySubscriptersCore();
}
private void NotifySubscriptersCore()
{
foreach (var observer in _observers)
{
NotifySubscriber(observer, _lastResult);
}
}
private void NotifySubscriber(IObserver<SubchannelReporterResult> observer, SubchannelReporterResult result)
{
observer.OnNext(result);
}
public IDisposable Subscribe(IObserver<SubchannelReporterResult> observer)
{
_observers.Add(observer);
return new Subscription(this, observer);
}
private void Unsubscribe(IObserver<SubchannelReporterResult> observer)
{
_observers.Remove(observer);
}
private class Subscription : IDisposable
{
private readonly SubchannelReporter _reporter;
private readonly IObserver<SubchannelReporterResult> _observer;
public Subscription(SubchannelReporter reporter, IObserver<SubchannelReporterResult> observer)
{
_reporter = reporter;
_observer = observer;
}
public void Dispose()
{
_reporter.Unsubscribe(_observer);
}
}
}
public record SubchannelReporterResult(ConnectivityState State, List<ReportedSubchannelState> Subchannels);
}

View File

@ -1,14 +0,0 @@
FROM mcr.microsoft.com/dotnet/sdk:10.0-preview AS build-env
WORKDIR /app
# Copy everything
COPY . ./
RUN dotnet --info
RUN dotnet restore examples/Container/Frontend
RUN dotnet publish examples/Container/Frontend -c Release -o out
# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:10.0-preview
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "Frontend.dll"]

View File

@ -1,18 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<!-- Suppress obsolete error in code generated by Razor. -->
<!-- CS0618: 'Router.PreferExactMatches' is obsolete: 'This property is obsolete and configuring it has not effect.' -->
<NoWarn>$(NoWarn);CS0618</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" />
<PackageReference Include="Grpc.Tools" PrivateAssets="All" />
<PackageReference Include="Grpc.Net.Client" />
<Protobuf Include="..\Proto\weather.proto" GrpcServices="Client" Link="Protos\weather.proto" Access="Internal" />
</ItemGroup>
</Project>

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