Merge pull request #23114 from jtattermusch/csharp_xds_example

Add C# XDS example
pull/23121/head
Jan Tattermusch 5 years ago committed by GitHub
commit 8f0e8275c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 34
      examples/csharp/Xds/Greeter.sln
  2. 20
      examples/csharp/Xds/Greeter/Greeter.csproj
  3. 12
      examples/csharp/Xds/GreeterClient/GreeterClient.csproj
  4. 51
      examples/csharp/Xds/GreeterClient/Program.cs
  5. 12
      examples/csharp/Xds/GreeterServer/GreeterServer.csproj
  6. 93
      examples/csharp/Xds/GreeterServer/Program.cs
  7. 99
      examples/csharp/Xds/README.md

@ -0,0 +1,34 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26228.4
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greeter", "Greeter\Greeter.csproj", "{13B6DFC8-F5F6-4CC2-99DF-57A7CF042033}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreeterClient", "GreeterClient\GreeterClient.csproj", "{B754FB02-D501-4308-8B89-33AB7119C80D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreeterServer", "GreeterServer\GreeterServer.csproj", "{DDBFF994-E076-43AD-B18D-049DFC1B670C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{13B6DFC8-F5F6-4CC2-99DF-57A7CF042033}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{13B6DFC8-F5F6-4CC2-99DF-57A7CF042033}.Debug|Any CPU.Build.0 = Debug|Any CPU
{13B6DFC8-F5F6-4CC2-99DF-57A7CF042033}.Release|Any CPU.ActiveCfg = Release|Any CPU
{13B6DFC8-F5F6-4CC2-99DF-57A7CF042033}.Release|Any CPU.Build.0 = Release|Any CPU
{B754FB02-D501-4308-8B89-33AB7119C80D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B754FB02-D501-4308-8B89-33AB7119C80D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B754FB02-D501-4308-8B89-33AB7119C80D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B754FB02-D501-4308-8B89-33AB7119C80D}.Release|Any CPU.Build.0 = Release|Any CPU
{DDBFF994-E076-43AD-B18D-049DFC1B670C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DDBFF994-E076-43AD-B18D-049DFC1B670C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DDBFF994-E076-43AD-B18D-049DFC1B670C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DDBFF994-E076-43AD-B18D-049DFC1B670C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.12.2" />
<PackageReference Include="Grpc.Core" Version="2.29.0" />
<PackageReference Include="Grpc.HealthCheck" Version="2.29.0" />
<PackageReference Include="Grpc.Reflection" Version="2.29.0"/>
<PackageReference Include="CommandLineParser" Version="2.8.0" />
<PackageReference Include="Grpc.Tools" Version="2.29.0" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
<Protobuf Include="../../../protos/helloworld.proto" Link="helloworld.proto" />
</ItemGroup>
</Project>

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Greeter\Greeter.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,51 @@
// Copyright 2015 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.
using System;
using Grpc.Core;
using Helloworld;
using CommandLine;
namespace GreeterClient
{
class Program
{
private class Options
{
[Option("server", Default = "localhost:50051", HelpText = "The address of the server")]
public string Server { get; set; }
}
public static void Main(string[] args)
{
Parser.Default.ParseArguments<Options>(args)
.WithParsed<Options>(options => RunClient(options));
}
private static void RunClient(Options options)
{
Channel channel = new Channel(options.Server, ChannelCredentials.Insecure);
var client = new Greeter.GreeterClient(channel);
String user = "you";
var reply = client.SayHello(new HelloRequest { Name = user });
Console.WriteLine("Greeter client received: " + reply.Message);
channel.ShutdownAsync().Wait();
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
}
}

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Greeter\Greeter.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,93 @@
// Copyright 2020 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.
using System;
using System.Net;
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.HealthCheck;
using Helloworld;
using Grpc.Health;
using Grpc.Health.V1;
using Grpc.Reflection;
using Grpc.Reflection.V1Alpha;
using CommandLine;
namespace GreeterServer
{
class GreeterImpl : Greeter.GreeterBase
{
private string hostname;
public GreeterImpl(string hostname)
{
this.hostname = hostname;
}
// Server side handler of the SayHello RPC
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
return Task.FromResult(new HelloReply { Message = $"Hello {request.Name} from {hostname}!"});
}
}
class Program
{
class Options
{
[Option("port", Default = 50051, HelpText = "The port to listen on.")]
public int Port { get; set; }
[Option("hostname", Required = false, HelpText = "The name clients will see in responses. If not specified, machine's hostname will obtain automatically.")]
public string Hostname { get; set; }
}
public static void Main(string[] args)
{
Parser.Default.ParseArguments<Options>(args)
.WithParsed<Options>(options => RunServer(options));
}
private static void RunServer(Options options)
{
var hostName = options.Hostname ?? Dns.GetHostName();
var serviceDescriptors = new [] {Greeter.Descriptor, Health.Descriptor, ServerReflection.Descriptor};
var greeterImpl = new GreeterImpl(hostName);
var healthServiceImpl = new HealthServiceImpl();
var reflectionImpl = new ReflectionServiceImpl(serviceDescriptors);
Server server = new Server
{
Services = { Greeter.BindService(greeterImpl), Health.BindService(healthServiceImpl), ServerReflection.BindService(reflectionImpl) },
Ports = { new ServerPort("[::]", options.Port, ServerCredentials.Insecure) }
};
server.Start();
// Mark all services as healthy.
foreach (var serviceDescriptor in serviceDescriptors)
{
healthServiceImpl.SetStatus(serviceDescriptor.FullName, HealthCheckResponse.Types.ServingStatus.Serving);
}
// Mark overall server status as healthy.
healthServiceImpl.SetStatus("", HealthCheckResponse.Types.ServingStatus.Serving);
Console.WriteLine("Greeter server listening on port " + options.Port);
Console.WriteLine("Press any key to stop the server...");
Console.ReadKey();
server.ShutdownAsync().Wait();
}
}
}

@ -0,0 +1,99 @@
gRPC Hostname example (C#)
========================
BACKGROUND
-------------
This is a version of the helloworld example with a server whose response includes its hostname. It also supports health and reflection services. This makes it a good server to test infrastructure, such as XDS load balancing.
PREREQUISITES
-------------
- The [.NET Core SDK 2.1+](https://www.microsoft.com/net/core)
You can also build the solution `Greeter.sln` using Visual Studio 2019,
but it's not a requirement.
RUN THE EXAMPLE
-------------
First, build and run the server, then verify the server is running and
check the server is behaving as expected (more on that below).
```
cd GreeterServer
dotnet run
```
After configuring your xDS server to track the gRPC server we just started,
create a bootstrap file as desribed in [gRFC A27](https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md):
```
{
xds_servers": [
{
"server_uri": <string containing URI of xds server>,
"channel_creds": [
{
"type": <string containing channel cred type>,
"config": <JSON object containing config for the type>
}
]
}
],
"node": <JSON form of Node proto>
}
```
Then point the `GRPC_XDS_BOOTSTRAP` environment variable at the bootstrap file:
```
export GRPC_XDS_BOOTSTRAP=/etc/xds-bootstrap.json
```
Finally, run your client:
```
cd GreeterClient
dotnet run --server xds-experimental:///my-backend
```
VERIFYING THE SERVER
-------------
`grpcurl` can be used to test your server. If you don't have it,
install [`grpcurl`](https://github.com/fullstorydev/grpcurl/releases). This will allow
you to manually test the service.
Exercise your server's application-layer service:
```sh
> grpcurl --plaintext -d '{"name": "you"}' localhost:50051
{
"message": "Hello you from jtatt.muc.corp.google.com!"
}
```
Make sure that all of your server's services are available via reflection:
```sh
> grpcurl --plaintext localhost:50051 list
grpc.health.v1.Health
grpc.reflection.v1alpha.ServerReflection
helloworld.Greeter
```
Make sure that your services are reporting healthy:
```sh
> grpcurl --plaintext -d '{"service": "helloworld.Greeter"}' localhost:50051
grpc.health.v1.Health/Check
{
"status": "SERVING"
}
> grpcurl --plaintext -d '{"service": ""}' localhost:50051
grpc.health.v1.Health/Check
{
"status": "SERVING"
}
```
Loading…
Cancel
Save