一、引言
本文采用gRPC官方提供的一个教程例子,通过这个例子可以学习到在.proto文件中定义服务。使用protocol buffer编译器生成服务器和客户端代码。使用C#gRPC API为您的服务编写简单的客户端和服务器。具体可参看:https://grpc.io/docs/tutorials/basic/csharp/
二、具体步骤
- 定义.proto文件
// 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. syntax = "proto3"; option java_multiple_files = true; option java_package = "io.grpc.examples.routeguide"; option java_outer_classname = "RouteGuideProto"; option objc_class_prefix = "RTG"; package routeguide; // Interface exported by the server. service RouteGuide { // A simple RPC. // // Obtains the feature at a given position. // // A feature with an empty name is returned if there's no feature at the given // position. rpc GetFeature(Point) returns (Feature) {} // A server-to-client streaming RPC. // // Obtains the Features available within the given Rectangle. Results are // streamed rather than returned at once (e.g. in a response message with a // repeated field), as the rectangle may cover a large area and contain a // huge number of features. rpc ListFeatures(Rectangle) returns (stream Feature) {} // A client-to-server streaming RPC. // // Accepts a stream of Points on a route being traversed, returning a // RouteSummary when traversal is completed. rpc RecordRoute(stream Point) returns (RouteSummary) {} // A Bidirectional streaming RPC. // // Accepts a stream of RouteNotes sent while a route is being traversed, // while receiving other RouteNotes (e.g. from other users). rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} } // Points are represented as latitude-longitude pairs in the E7 representation // (degrees multiplied by 10**7 and rounded to the nearest integer). // Latitudes should be in the range +/- 90 degrees and longitude should be in // the range +/- 180 degrees (inclusive). message Point { int32 latitude = 1; int32 longitude = 2; } // A latitude-longitude rectangle, represented as two diagonally opposite // points "lo" and "hi". message Rectangle { // One corner of the rectangle. Point lo = 1; // The other corner of the rectangle. Point hi = 2; } // A feature names something at a given point. // // If a feature could not be named, the name is empty. message Feature { // The name of the feature. string name = 1; // The point where the feature is detected. Point location = 2; } // A RouteNote is a message sent while at a given point. message RouteNote { // The location from which the message is sent. Point location = 1; // The message to be sent. string message = 2; } // A RouteSummary is received in response to a RecordRoute rpc. // // It contains the number of individual points received, the number of // detected features, and the total distance covered as the cumulative sum of // the distance between each point. message RouteSummary { // The number of points received. int32 point_count = 1; // The number of known features passed while traversing the route. int32 feature_count = 2; // The distance covered in metres. int32 distance = 3; // The duration of the traversal in seconds. int32 elapsed_time = 4; }
- 需要引入Nuget包
Install-Package Google.Protobuf Install-Package Grpc Install-Package Grpc.Tools
- 生成客户端和服务器代码,在Grpc.Tools 1.17版本之后
Grpc.Tools
NuGet包与MSBuild集成从.proto文件自动生成C#代码。但是在1.17以前的版本需要使用protoc.exe和grpc_csharp_plugin.exe 来生成代码,如下命令:
protoc -I . --csharp_out . --grpc_out . --plugin=protoc-gen-grpc=grpc_csharp_plugin.exe Helloworld.proto
在Grpc.Tools 1.17版本之后只需要使用donet build RouteGuid.sln或者直接在Visual Studio构建项目来完成,构建重新生成目录下的以下文件RouteGuide/obj/Debug/TARGET_FRAMEWORK
:RouteGuide.cs和RouteGuideGrpc.cs
// <auto-generated> // Generated by the protocol buffer compiler. DO NOT EDIT! // source: route_guide.proto // </auto-generated> #pragma warning disable 1591, 0612, 3021 #region Designer generated code using pb = global::Google.Protobuf; using pbc = global::Google.Protobuf.Collections; using pbr = global::Google.Protobuf.Reflection; using scg = global::System.Collections.Generic; namespace Routeguide { /// <summary>Holder for reflection information generated from route_guide.proto</summary> public static partial class RouteGuideReflection { #region Descriptor /// <summary>File descriptor for route_guide.proto</summary> public static pbr::FileDescriptor Descriptor { get { return descriptor; } } private static pbr::FileDescriptor descriptor; static RouteGuideReflection() { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "ChFyb3V0ZV9ndWlkZS5wcm90bxIKcm91dGVndWlkZSIsCgVQb2ludBIQCghs", "YXRpdHVkZRgBIAEoBRIRCglsb25naXR1ZGUYAiABKAUiSQoJUmVjdGFuZ2xl", "Eh0KAmxvGAEgASgLMhEucm91dGVndWlkZS5Qb2ludBIdCgJoaRgCIAEoCzIR", "LnJvdXRlZ3VpZGUuUG9pbnQiPAoHRmVhdHVyZRIMCgRuYW1lGAEgASgJEiMK", "CGxvY2F0aW9uGAIgASgLMhEucm91dGVndWlkZS5Qb2ludCJBCglSb3V0ZU5v", "dGUSIwoIbG9jYXRpb24YASABKAsyES5yb3V0ZWd1aWRlLlBvaW50Eg8KB21l", "c3NhZ2UYAiABKAkiYgoMUm91dGVTdW1tYXJ5EhMKC3BvaW50X2NvdW50GAEg", "ASgFEhUKDWZlYXR1cmVfY291bnQYAiABKAUSEAoIZGlzdGFuY2UYAyABKAUS", "FAoMZWxhcHNlZF90aW1lGAQgASgFMoUCCgpSb3V0ZUd1aWRlEjYKCkdldEZl", "YXR1cmUSES5yb3V0ZWd1aWRlLlBvaW50GhMucm91dGVndWlkZS5GZWF0dXJl", "IgASPgoMTGlzdEZlYXR1cmVzEhUucm91dGVndWlkZS5SZWN0YW5nbGUaEy5y", "b3V0ZWd1aWRlLkZlYXR1cmUiADABEj4KC1JlY29yZFJvdXRlEhEucm91dGVn", "dWlkZS5Qb2ludBoYLnJvdXRlZ3VpZGUuUm91dGVTdW1tYXJ5IgAoARI/CglS", "b3V0ZUNoYXQSFS5yb3V0ZWd1aWRlLlJvdXRlTm90ZRoVLnJvdXRlZ3VpZGUu", "Um91dGVOb3RlIgAoATABQjYKG2lvLmdycGMuZXhhbXBsZXMucm91dGVndWlk", "ZUIPUm91dGVHdWlkZVByb3RvUAGiAgNSVEdiBnByb3RvMw==")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { }, new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Routeguide.Point), global::Routeguide.Point.Parser, new[]{ "Latitude", "Longitude" }, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Routeguide.Rectangle), global::Routeguide.Rectangle.Parser, new[]{ "Lo", "Hi" }, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Routeguide.Feature), global::Routeguide.Feature.Parser, new[]{ "Name", "Location" }, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Routeguide.RouteNote), global::Routeguide.RouteNote.Parser, new[]{ "Location", "Message" }, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Routeguide.RouteSummary), global::Routeguide.RouteSummary.Parser, new[]{ "PointCount", "FeatureCount", "Distance", "ElapsedTime" }, null, null, null) })); } #endregion } #region Messages /// <summary> /// Points are represented as latitude-longitude pairs in the E7 representation /// (degrees multiplied by 10**7 and rounded to the nearest integer). /// Latitudes should be in the range +/- 90 degrees and longitude should be in /// the range +/- 180 degrees (inclusive). /// </summary> public sealed partial class Point : pb::IMessage<Point> { private static readonly pb::MessageParser<Point> _parser = new pb::MessageParser<Point>(() => new Point()); private pb::UnknownFieldSet _unknownFields; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<Point> Parser { get { return _parser; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Routeguide.RouteGuideReflection.Descriptor.MessageTypes[0]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Point() { OnConstruction(); } partial void OnConstruction(); [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Point(Point other) : this() { latitude_ = other.latitude_; longitude_ = other.longitude_; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Point Clone() { return new Point(this); } /// <summary>Field number for the "latitude" field.</summary> public const int LatitudeFieldNumber = 1; private int latitude_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int Latitude { get { return latitude_; } set { latitude_ = value; } } /// <summary>Field number for the "longitude" field.</summary> public const int LongitudeFieldNumber = 2; private int longitude_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int Longitude { get { return longitude_; } set { longitude_ = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as Point); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(Point other) { if (ReferenceEquals(other, null)) { return false; } if (ReferenceEquals(other, this)) { return true; } if (Latitude != other.Latitude) return false; if (Longitude != other.Longitude) return false; return Equals(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (Latitude != 0) hash ^= Latitude.GetHashCode(); if (Longitude != 0) hash ^= Longitude.GetHashCode(); if (_unknownFields != null) { hash ^= _unknownFields.GetHashCode(); } return hash; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (Latitude != 0) { output.WriteRawTag(8); output.WriteInt32(Latitude); } if (Longitude != 0) { output.WriteRawTag(16); output.WriteInt32(Longitude); } if (_unknownFields != null) { _unknownFields.WriteTo(output); } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (Latitude != 0) { size += 1 + pb::CodedOutputStream.ComputeInt32Size(Latitude); } if (Longitude != 0) { size += 1 + pb::CodedOutputStream.ComputeInt32Size(Longitude); } if (_unknownFields != null) { size += _unknownFields.CalculateSize(); } return size; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(Point other) { if (other == null) { return; } if (other.Latitude != 0) { Latitude = other.Latitude; } if (other.Longitude != 0) { Longitude = other.Longitude; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; case 8: { Latitude = input.ReadInt32(); break; } case 16: { Longitude = input.ReadInt32(); break; } } } } } /// <summary> /// A latitude-longitude rectangle, represented as two diagonally opposite /// points "lo" and "hi". /// </summary> public sealed partial class Rectangle : pb::IMessage<Rectangle> { private static readonly pb::MessageParser<Rectangle> _parser = new pb::MessageParser<Rectangle>(() => new Rectangle()); private pb::UnknownFieldSet _unknownFields; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<Rectangle> Parser { get { return _parser; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Routeguide.RouteGuideReflection.Descriptor.MessageTypes[1]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Rectangle() { OnConstruction(); } partial void OnConstruction(); [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Rectangle(Rectangle other) : this() { lo_ = other.lo_ != null ? other.lo_.Clone() : null; hi_ = other.hi_ != null ? other.hi_.Clone() : null; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Rectangle Clone() { return new Rectangle(this); } /// <summary>Field number for the "lo" field.</summary> public const int LoFieldNumber = 1; private global::Routeguide.Point lo_; /// <summary> /// One corner of the rectangle. /// </summary> [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Routeguide.Point Lo { get { return lo_; } set { lo_ = value; } } /// <summary>Field number for the "hi" field.</summary> public const int HiFieldNumber = 2; private global::Routeguide.Point hi_; /// <summary> /// The other corner of the rectangle. /// </summary> [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Routeguide.Point Hi { get { return hi_; } set { hi_ = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as Rectangle); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(Rectangle other) { if (ReferenceEquals(other, null)) { return false; } if (ReferenceEquals(other, this)) { return true; } if (!object.Equals(Lo, other.Lo)) return false; if (!object.Equals(Hi, other.Hi)) return false; return Equals(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (lo_ != null) hash ^= Lo.GetHashCode(); if (hi_ != null) hash ^= Hi.GetHashCode(); if (_unknownFields != null) { hash ^= _unknownFields.GetHashCode(); } return hash; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (lo_ != null) { output.WriteRawTag(10); output.WriteMessage(Lo); } if (hi_ != null) { output.WriteRawTag(18); output.WriteMessage(Hi); } if (_unknownFields != null) { _unknownFields.WriteTo(output); } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (lo_ != null) { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Lo); } if (hi_ != null) { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Hi); } if (_unknownFields != null) { size += _unknownFields.CalculateSize(); } return size; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(Rectangle other) { if (other == null) { return; } if (other.lo_ != null) { if (lo_ == null) { lo_ = new global::Routeguide.Point(); } Lo.MergeFrom(other.Lo); } if (other.hi_ != null) { if (hi_ == null) { hi_ = new global::Routeguide.Point(); } Hi.MergeFrom(other.Hi); } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; case 10: { if (lo_ == null) { lo_ = new global::Routeguide.Point(); } input.ReadMessage(lo_); break; } case 18: { if (hi_ == null) { hi_ = new global::Routeguide.Point(); } input.ReadMessage(hi_); break; } } } } } /// <summary> /// A feature names something at a given point. /// /// If a feature could not be named, the name is empty. /// </summary> public sealed partial class Feature : pb::IMessage<Feature> { private static readonly pb::MessageParser<Feature> _parser = new pb::MessageParser<Feature>(() => new Feature()); private pb::UnknownFieldSet _unknownFields; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<Feature> Parser { get { return _parser; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Routeguide.RouteGuideReflection.Descriptor.MessageTypes[2]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Feature() { OnConstruction(); } partial void OnConstruction(); [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Feature(Feature other) : this() { name_ = other.name_; location_ = other.location_ != null ? other.location_.Clone() : null; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Feature Clone() { return new Feature(this); } /// <summary>Field number for the "name" field.</summary> public const int NameFieldNumber = 1; private string name_ = ""; /// <summary> /// The name of the feature. /// </summary> [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public string Name { get { return name_; } set { name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// <summary>Field number for the "location" field.</summary> public const int LocationFieldNumber = 2; private global::Routeguide.Point location_; /// <summary> /// The point where the feature is detected. /// </summary> [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Routeguide.Point Location { get { return location_; } set { location_ = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as Feature); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(Feature other) { if (ReferenceEquals(other, null)) { return false; } if (ReferenceEquals(other, this)) { return true; } if (Name != other.Name) return false; if (!object.Equals(Location, other.Location)) return false; return Equals(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (Name.Length != 0) hash ^= Name.GetHashCode(); if (location_ != null) hash ^= Location.GetHashCode(); if (_unknownFields != null) { hash ^= _unknownFields.GetHashCode(); } return hash; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (Name.Length != 0) { output.WriteRawTag(10); output.WriteString(Name); } if (location_ != null) { output.WriteRawTag(18); output.WriteMessage(Location); } if (_unknownFields != null) { _unknownFields.WriteTo(output); } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (Name.Length != 0) { size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); } if (location_ != null) { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Location); } if (_unknownFields != null) { size += _unknownFields.CalculateSize(); } return size; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(Feature other) { if (other == null) { return; } if (other.Name.Length != 0) { Name = other.Name; } if (other.location_ != null) { if (location_ == null) { location_ = new global::Routeguide.Point(); } Location.MergeFrom(other.Location); } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; case 10: { Name = input.ReadString(); break; } case 18: { if (location_ == null) { location_ = new global::Routeguide.Point(); } input.ReadMessage(location_); break; } } } } } /// <summary> /// A RouteNote is a message sent while at a given point. /// </summary> public sealed partial class RouteNote : pb::IMessage<RouteNote> { private static readonly pb::MessageParser<RouteNote> _parser = new pb::MessageParser<RouteNote>(() => new RouteNote()); private pb::UnknownFieldSet _unknownFields; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<RouteNote> Parser { get { return _parser; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Routeguide.RouteGuideReflection.Descriptor.MessageTypes[3]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public RouteNote() { OnConstruction(); } partial void OnConstruction(); [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public RouteNote(RouteNote other) : this() { location_ = other.location_ != null ? other.location_.Clone() : null; message_ = other.message_; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public RouteNote Clone() { return new RouteNote(this); } /// <summary>Field number for the "location" field.</summary> public const int LocationFieldNumber = 1; private global::Routeguide.Point location_; /// <summary> /// The location from which the message is sent. /// </summary> [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Routeguide.Point Location { get { return location_; } set { location_ = value; } } /// <summary>Field number for the "message" field.</summary> public const int MessageFieldNumber = 2; private string message_ = ""; /// <summary> /// The message to be sent. /// </summary> [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public string Message { get { return message_; } set { message_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as RouteNote); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(RouteNote other) { if (ReferenceEquals(other, null)) { return false; } if (ReferenceEquals(other, this)) { return true; } if (!object.Equals(Location, other.Location)) return false; if (Message != other.Message) return false; return Equals(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (location_ != null) hash ^= Location.GetHashCode(); if (Message.Length != 0) hash ^= Message.GetHashCode(); if (_unknownFields != null) { hash ^= _unknownFields.GetHashCode(); } return hash; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (location_ != null) { output.WriteRawTag(10); output.WriteMessage(Location); } if (Message.Length != 0) { output.WriteRawTag(18); output.WriteString(Message); } if (_unknownFields != null) { _unknownFields.WriteTo(output); } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (location_ != null) { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Location); } if (Message.Length != 0) { size += 1 + pb::CodedOutputStream.ComputeStringSize(Message); } if (_unknownFields != null) { size += _unknownFields.CalculateSize(); } return size; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(RouteNote other) { if (other == null) { return; } if (other.location_ != null) { if (location_ == null) { location_ = new global::Routeguide.Point(); } Location.MergeFrom(other.Location); } if (other.Message.Length != 0) { Message = other.Message; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; case 10: { if (location_ == null) { location_ = new global::Routeguide.Point(); } input.ReadMessage(location_); break; } case 18: { Message = input.ReadString(); break; } } } } } /// <summary> /// A RouteSummary is received in response to a RecordRoute rpc. /// /// It contains the number of individual points received, the number of /// detected features, and the total distance covered as the cumulative sum of /// the distance between each point. /// </summary> public sealed partial class RouteSummary : pb::IMessage<RouteSummary> { private static readonly pb::MessageParser<RouteSummary> _parser = new pb::MessageParser<RouteSummary>(() => new RouteSummary()); private pb::UnknownFieldSet _unknownFields; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<RouteSummary> Parser { get { return _parser; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Routeguide.RouteGuideReflection.Descriptor.MessageTypes[4]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public RouteSummary() { OnConstruction(); } partial void OnConstruction(); [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public RouteSummary(RouteSummary other) : this() { pointCount_ = other.pointCount_; featureCount_ = other.featureCount_; distance_ = other.distance_; elapsedTime_ = other.elapsedTime_; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public RouteSummary Clone() { return new RouteSummary(this); } /// <summary>Field number for the "point_count" field.</summary> public const int PointCountFieldNumber = 1; private int pointCount_; /// <summary> /// The number of points received. /// </summary> [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int PointCount { get { return pointCount_; } set { pointCount_ = value; } } /// <summary>Field number for the "feature_count" field.</summary> public const int FeatureCountFieldNumber = 2; private int featureCount_; /// <summary> /// The number of known features passed while traversing the route. /// </summary> [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int FeatureCount { get { return featureCount_; } set { featureCount_ = value; } } /// <summary>Field number for the "distance" field.</summary> public const int DistanceFieldNumber = 3; private int distance_; /// <summary> /// The distance covered in metres. /// </summary> [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int Distance { get { return distance_; } set { distance_ = value; } } /// <summary>Field number for the "elapsed_time" field.</summary> public const int ElapsedTimeFieldNumber = 4; private int elapsedTime_; /// <summary> /// The duration of the traversal in seconds. /// </summary> [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int ElapsedTime { get { return elapsedTime_; } set { elapsedTime_ = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as RouteSummary); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(RouteSummary other) { if (ReferenceEquals(other, null)) { return false; } if (ReferenceEquals(other, this)) { return true; } if (PointCount != other.PointCount) return false; if (FeatureCount != other.FeatureCount) return false; if (Distance != other.Distance) return false; if (ElapsedTime != other.ElapsedTime) return false; return Equals(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (PointCount != 0) hash ^= PointCount.GetHashCode(); if (FeatureCount != 0) hash ^= FeatureCount.GetHashCode(); if (Distance != 0) hash ^= Distance.GetHashCode(); if (ElapsedTime != 0) hash ^= ElapsedTime.GetHashCode(); if (_unknownFields != null) { hash ^= _unknownFields.GetHashCode(); } return hash; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (PointCount != 0) { output.WriteRawTag(8); output.WriteInt32(PointCount); } if (FeatureCount != 0) { output.WriteRawTag(16); output.WriteInt32(FeatureCount); } if (Distance != 0) { output.WriteRawTag(24); output.WriteInt32(Distance); } if (ElapsedTime != 0) { output.WriteRawTag(32); output.WriteInt32(ElapsedTime); } if (_unknownFields != null) { _unknownFields.WriteTo(output); } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (PointCount != 0) { size += 1 + pb::CodedOutputStream.ComputeInt32Size(PointCount); } if (FeatureCount != 0) { size += 1 + pb::CodedOutputStream.ComputeInt32Size(FeatureCount); } if (Distance != 0) { size += 1 + pb::CodedOutputStream.ComputeInt32Size(Distance); } if (ElapsedTime != 0) { size += 1 + pb::CodedOutputStream.ComputeInt32Size(ElapsedTime); } if (_unknownFields != null) { size += _unknownFields.CalculateSize(); } return size; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(RouteSummary other) { if (other == null) { return; } if (other.PointCount != 0) { PointCount = other.PointCount; } if (other.FeatureCount != 0) { FeatureCount = other.FeatureCount; } if (other.Distance != 0) { Distance = other.Distance; } if (other.ElapsedTime != 0) { ElapsedTime = other.ElapsedTime; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; case 8: { PointCount = input.ReadInt32(); break; } case 16: { FeatureCount = input.ReadInt32(); break; } case 24: { Distance = input.ReadInt32(); break; } case 32: { ElapsedTime = input.ReadInt32(); break; } } } } } #endregion } #endregion Designer generated code
// <auto-generated> // Generated by the protocol buffer compiler. DO NOT EDIT! // source: route_guide.proto // </auto-generated> // Original file comments: // 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. // #pragma warning disable 0414, 1591 #region Designer generated code using grpc = global::Grpc.Core; namespace Routeguide { /// <summary> /// Interface exported by the server. /// </summary> public static partial class RouteGuide { static readonly string __ServiceName = "routeguide.RouteGuide"; static readonly grpc::Marshaller<global::Routeguide.Point> __Marshaller_routeguide_Point = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Routeguide.Point.Parser.ParseFrom); static readonly grpc::Marshaller<global::Routeguide.Feature> __Marshaller_routeguide_Feature = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Routeguide.Feature.Parser.ParseFrom); static readonly grpc::Marshaller<global::Routeguide.Rectangle> __Marshaller_routeguide_Rectangle = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Routeguide.Rectangle.Parser.ParseFrom); static readonly grpc::Marshaller<global::Routeguide.RouteSummary> __Marshaller_routeguide_RouteSummary = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Routeguide.RouteSummary.Parser.ParseFrom); static readonly grpc::Marshaller<global::Routeguide.RouteNote> __Marshaller_routeguide_RouteNote = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Routeguide.RouteNote.Parser.ParseFrom); static readonly grpc::Method<global::Routeguide.Point, global::Routeguide.Feature> __Method_GetFeature = new grpc::Method<global::Routeguide.Point, global::Routeguide.Feature>( grpc::MethodType.Unary, __ServiceName, "GetFeature", __Marshaller_routeguide_Point, __Marshaller_routeguide_Feature); static readonly grpc::Method<global::Routeguide.Rectangle, global::Routeguide.Feature> __Method_ListFeatures = new grpc::Method<global::Routeguide.Rectangle, global::Routeguide.Feature>( grpc::MethodType.ServerStreaming, __ServiceName, "ListFeatures", __Marshaller_routeguide_Rectangle, __Marshaller_routeguide_Feature); static readonly grpc::Method<global::Routeguide.Point, global::Routeguide.RouteSummary> __Method_RecordRoute = new grpc::Method<global::Routeguide.Point, global::Routeguide.RouteSummary>( grpc::MethodType.ClientStreaming, __ServiceName, "RecordRoute", __Marshaller_routeguide_Point, __Marshaller_routeguide_RouteSummary); static readonly grpc::Method<global::Routeguide.RouteNote, global::Routeguide.RouteNote> __Method_RouteChat = new grpc::Method<global::Routeguide.RouteNote, global::Routeguide.RouteNote>( grpc::MethodType.DuplexStreaming, __ServiceName, "RouteChat", __Marshaller_routeguide_RouteNote, __Marshaller_routeguide_RouteNote); /// <summary>Service descriptor</summary> public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor { get { return global::Routeguide.RouteGuideReflection.Descriptor.Services[0]; } } /// <summary>Base class for server-side implementations of RouteGuide</summary> public abstract partial class RouteGuideBase { /// <summary> /// A simple RPC. /// /// Obtains the feature at a given position. /// /// A feature with an empty name is returned if there's no feature at the given /// position. /// </summary> /// <param name="request">The request received from the client.</param> /// <param name="context">The context of the server-side call handler being invoked.</param> /// <returns>The response to send back to the client (wrapped by a task).</returns> public virtual global::System.Threading.Tasks.Task<global::Routeguide.Feature> GetFeature(global::Routeguide.Point request, grpc::ServerCallContext context) { throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); } /// <summary> /// A server-to-client streaming RPC. /// /// Obtains the Features available within the given Rectangle. Results are /// streamed rather than returned at once (e.g. in a response message with a /// repeated field), as the rectangle may cover a large area and contain a /// huge number of features. /// </summary> /// <param name="request">The request received from the client.</param> /// <param name="responseStream">Used for sending responses back to the client.</param> /// <param name="context">The context of the server-side call handler being invoked.</param> /// <returns>A task indicating completion of the handler.</returns> public virtual global::System.Threading.Tasks.Task ListFeatures(global::Routeguide.Rectangle request, grpc::IServerStreamWriter<global::Routeguide.Feature> responseStream, grpc::ServerCallContext context) { throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); } /// <summary> /// A client-to-server streaming RPC. /// /// Accepts a stream of Points on a route being traversed, returning a /// RouteSummary when traversal is completed. /// </summary> /// <param name="requestStream">Used for reading requests from the client.</param> /// <param name="context">The context of the server-side call handler being invoked.</param> /// <returns>The response to send back to the client (wrapped by a task).</returns> public virtual global::System.Threading.Tasks.Task<global::Routeguide.RouteSummary> RecordRoute(grpc::IAsyncStreamReader<global::Routeguide.Point> requestStream, grpc::ServerCallContext context) { throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); } /// <summary> /// A Bidirectional streaming RPC. /// /// Accepts a stream of RouteNotes sent while a route is being traversed, /// while receiving other RouteNotes (e.g. from other users). /// </summary> /// <param name="requestStream">Used for reading requests from the client.</param> /// <param name="responseStream">Used for sending responses back to the client.</param> /// <param name="context">The context of the server-side call handler being invoked.</param> /// <returns>A task indicating completion of the handler.</returns> public virtual global::System.Threading.Tasks.Task RouteChat(grpc::IAsyncStreamReader<global::Routeguide.RouteNote> requestStream, grpc::IServerStreamWriter<global::Routeguide.RouteNote> responseStream, grpc::ServerCallContext context) { throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); } } /// <summary>Client for RouteGuide</summary> public partial class RouteGuideClient : grpc::ClientBase<RouteGuideClient> { /// <summary>Creates a new client for RouteGuide</summary> /// <param name="channel">The channel to use to make remote calls.</param> public RouteGuideClient(grpc::Channel channel) : base(channel) { } /// <summary>Creates a new client for RouteGuide that uses a custom <c>CallInvoker</c>.</summary> /// <param name="callInvoker">The callInvoker to use to make remote calls.</param> public RouteGuideClient(grpc::CallInvoker callInvoker) : base(callInvoker) { } /// <summary>Protected parameterless constructor to allow creation of test doubles.</summary> protected RouteGuideClient() : base() { } /// <summary>Protected constructor to allow creation of configured clients.</summary> /// <param name="configuration">The client configuration.</param> protected RouteGuideClient(ClientBaseConfiguration configuration) : base(configuration) { } /// <summary> /// A simple RPC. /// /// Obtains the feature at a given position. /// /// A feature with an empty name is returned if there's no feature at the given /// position. /// </summary> /// <param name="request">The request to send to the server.</param> /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param> /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param> /// <param name="cancellationToken">An optional token for canceling the call.</param> /// <returns>The response received from the server.</returns> public virtual global::Routeguide.Feature GetFeature(global::Routeguide.Point request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) { return GetFeature(request, new grpc::CallOptions(headers, deadline, cancellationToken)); } /// <summary> /// A simple RPC. /// /// Obtains the feature at a given position. /// /// A feature with an empty name is returned if there's no feature at the given /// position. /// </summary> /// <param name="request">The request to send to the server.</param> /// <param name="options">The options for the call.</param> /// <returns>The response received from the server.</returns> public virtual global::Routeguide.Feature GetFeature(global::Routeguide.Point request, grpc::CallOptions options) { return CallInvoker.BlockingUnaryCall(__Method_GetFeature, null, options, request); } /// <summary> /// A simple RPC. /// /// Obtains the feature at a given position. /// /// A feature with an empty name is returned if there's no feature at the given /// position. /// </summary> /// <param name="request">The request to send to the server.</param> /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param> /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param> /// <param name="cancellationToken">An optional token for canceling the call.</param> /// <returns>The call object.</returns> public virtual grpc::AsyncUnaryCall<global::Routeguide.Feature> GetFeatureAsync(global::Routeguide.Point request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) { return GetFeatureAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); } /// <summary> /// A simple RPC. /// /// Obtains the feature at a given position. /// /// A feature with an empty name is returned if there's no feature at the given /// position. /// </summary> /// <param name="request">The request to send to the server.</param> /// <param name="options">The options for the call.</param> /// <returns>The call object.</returns> public virtual grpc::AsyncUnaryCall<global::Routeguide.Feature> GetFeatureAsync(global::Routeguide.Point request, grpc::CallOptions options) { return CallInvoker.AsyncUnaryCall(__Method_GetFeature, null, options, request); } /// <summary> /// A server-to-client streaming RPC. /// /// Obtains the Features available within the given Rectangle. Results are /// streamed rather than returned at once (e.g. in a response message with a /// repeated field), as the rectangle may cover a large area and contain a /// huge number of features. /// </summary> /// <param name="request">The request to send to the server.</param> /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param> /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param> /// <param name="cancellationToken">An optional token for canceling the call.</param> /// <returns>The call object.</returns> public virtual grpc::AsyncServerStreamingCall<global::Routeguide.Feature> ListFeatures(global::Routeguide.Rectangle request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) { return ListFeatures(request, new grpc::CallOptions(headers, deadline, cancellationToken)); } /// <summary> /// A server-to-client streaming RPC. /// /// Obtains the Features available within the given Rectangle. Results are /// streamed rather than returned at once (e.g. in a response message with a /// repeated field), as the rectangle may cover a large area and contain a /// huge number of features. /// </summary> /// <param name="request">The request to send to the server.</param> /// <param name="options">The options for the call.</param> /// <returns>The call object.</returns> public virtual grpc::AsyncServerStreamingCall<global::Routeguide.Feature> ListFeatures(global::Routeguide.Rectangle request, grpc::CallOptions options) { return CallInvoker.AsyncServerStreamingCall(__Method_ListFeatures, null, options, request); } /// <summary> /// A client-to-server streaming RPC. /// /// Accepts a stream of Points on a route being traversed, returning a /// RouteSummary when traversal is completed. /// </summary> /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param> /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param> /// <param name="cancellationToken">An optional token for canceling the call.</param> /// <returns>The call object.</returns> public virtual grpc::AsyncClientStreamingCall<global::Routeguide.Point, global::Routeguide.RouteSummary> RecordRoute(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) { return RecordRoute(new grpc::CallOptions(headers, deadline, cancellationToken)); } /// <summary> /// A client-to-server streaming RPC. /// /// Accepts a stream of Points on a route being traversed, returning a /// RouteSummary when traversal is completed. /// </summary> /// <param name="options">The options for the call.</param> /// <returns>The call object.</returns> public virtual grpc::AsyncClientStreamingCall<global::Routeguide.Point, global::Routeguide.RouteSummary> RecordRoute(grpc::CallOptions options) { return CallInvoker.AsyncClientStreamingCall(__Method_RecordRoute, null, options); } /// <summary> /// A Bidirectional streaming RPC. /// /// Accepts a stream of RouteNotes sent while a route is being traversed, /// while receiving other RouteNotes (e.g. from other users). /// </summary> /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param> /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param> /// <param name="cancellationToken">An optional token for canceling the call.</param> /// <returns>The call object.</returns> public virtual grpc::AsyncDuplexStreamingCall<global::Routeguide.RouteNote, global::Routeguide.RouteNote> RouteChat(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) { return RouteChat(new grpc::CallOptions(headers, deadline, cancellationToken)); } /// <summary> /// A Bidirectional streaming RPC. /// /// Accepts a stream of RouteNotes sent while a route is being traversed, /// while receiving other RouteNotes (e.g. from other users). /// </summary> /// <param name="options">The options for the call.</param> /// <returns>The call object.</returns> public virtual grpc::AsyncDuplexStreamingCall<global::Routeguide.RouteNote, global::Routeguide.RouteNote> RouteChat(grpc::CallOptions options) { return CallInvoker.AsyncDuplexStreamingCall(__Method_RouteChat, null, options); } /// <summary>Creates a new instance of client from given <c>ClientBaseConfiguration</c>.</summary> protected override RouteGuideClient NewInstance(ClientBaseConfiguration configuration) { return new RouteGuideClient(configuration); } } /// <summary>Creates service definition that can be registered with a server</summary> /// <param name="serviceImpl">An object implementing the server-side handling logic.</param> public static grpc::ServerServiceDefinition BindService(RouteGuideBase serviceImpl) { return grpc::ServerServiceDefinition.CreateBuilder() .AddMethod(__Method_GetFeature, serviceImpl.GetFeature) .AddMethod(__Method_ListFeatures, serviceImpl.ListFeatures) .AddMethod(__Method_RecordRoute, serviceImpl.RecordRoute) .AddMethod(__Method_RouteChat, serviceImpl.RouteChat).Build(); } /// <summary>Register service method implementations with a service binder. Useful when customizing the service binding logic. /// Note: this method is part of an experimental API that can change or be removed without any prior notice.</summary> /// <param name="serviceBinder">Service methods will be bound by calling <c>AddMethod</c> on this object.</param> /// <param name="serviceImpl">An object implementing the server-side handling logic.</param> public static void BindService(grpc::ServiceBinderBase serviceBinder, RouteGuideBase serviceImpl) { serviceBinder.AddMethod(__Method_GetFeature, serviceImpl.GetFeature); serviceBinder.AddMethod(__Method_ListFeatures, serviceImpl.ListFeatures); serviceBinder.AddMethod(__Method_RecordRoute, serviceImpl.RecordRoute); serviceBinder.AddMethod(__Method_RouteChat, serviceImpl.RouteChat); } } } #endregion
- 创建服务器
- 通过继承从我们的服务定义生成的基类来实现服务功能:执行我们服务的实际“工作”。
- 运行gRPC服务器以侦听来自客户端的请求并返回服务响应。
// 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 System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Utils; namespace Routeguide { /// <summary> /// Example implementation of RouteGuide server. /// </summary> public class RouteGuideImpl : RouteGuide.RouteGuideBase { readonly List<Feature> features; readonly object myLock = new object(); readonly Dictionary<Point, List<RouteNote>> routeNotes = new Dictionary<Point, List<RouteNote>>(); public RouteGuideImpl(List<Feature> features) { this.features = features; } /// <summary> /// Gets the feature at the requested point. If no feature at that location /// exists, an unnammed feature is returned at the provided location. /// </summary> public override Task<Feature> GetFeature(Point request, ServerCallContext context) { return Task.FromResult(CheckFeature(request)); } /// <summary> /// Gets all features contained within the given bounding rectangle. /// </summary> public override async Task ListFeatures(Rectangle request, IServerStreamWriter<Feature> responseStream, ServerCallContext context) { var responses = features.FindAll( (feature) => feature.Exists() && request.Contains(feature.Location) ); foreach (var response in responses) { await responseStream.WriteAsync(response); } } /// <summary> /// Gets a stream of points, and responds with statistics about the "trip": number of points, /// number of known features visited, total distance traveled, and total time spent. /// </summary> public override async Task<RouteSummary> RecordRoute(IAsyncStreamReader<Point> requestStream, ServerCallContext context) { int pointCount = 0; int featureCount = 0; int distance = 0; Point previous = null; var stopwatch = new Stopwatch(); stopwatch.Start(); while (await requestStream.MoveNext()) { var point = requestStream.Current; pointCount++; if (CheckFeature(point).Exists()) { featureCount++; } if (previous != null) { distance += (int) previous.GetDistance(point); } previous = point; } stopwatch.Stop(); return new RouteSummary { PointCount = pointCount, FeatureCount = featureCount, Distance = distance, ElapsedTime = (int)(stopwatch.ElapsedMilliseconds / 1000) }; } /// <summary> /// Receives a stream of message/location pairs, and responds with a stream of all previous /// messages at each of those locations. /// </summary> public override async Task RouteChat(IAsyncStreamReader<RouteNote> requestStream, IServerStreamWriter<RouteNote> responseStream, ServerCallContext context) { while (await requestStream.MoveNext()) { var note = requestStream.Current; List<RouteNote> prevNotes = AddNoteForLocation(note.Location, note); foreach (var prevNote in prevNotes) { await responseStream.WriteAsync(prevNote); } } } /// <summary> /// Adds a note for location and returns a list of pre-existing notes for that location (not containing the newly added note). /// </summary> private List<RouteNote> AddNoteForLocation(Point location, RouteNote note) { lock (myLock) { List<RouteNote> notes; if (!routeNotes.TryGetValue(location, out notes)) { notes = new List<RouteNote>(); routeNotes.Add(location, notes); } var preexistingNotes = new List<RouteNote>(notes); notes.Add(note); return preexistingNotes; } } /// <summary> /// Gets the feature at the given point. /// </summary> /// <param name="location">the location to check</param> /// <returns>The feature object at the point Note that an empty name indicates no feature.</returns> private Feature CheckFeature(Point location) { var result = features.FirstOrDefault((feature) => feature.Location.Equals(location)); if (result == null) { // No feature was found, return an unnamed feature. return new Feature { Name = "", Location = location }; } return result; } } }
// 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 Grpc.Core; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Routeguide { class Program { static void Main(string[] args) { const int Port = 50052; var features = RouteGuideUtil.ParseFeatures(RouteGuideUtil.DefaultFeaturesFile); Server server = new Server { Services = { RouteGuide.BindService(new RouteGuideImpl(features)) }, Ports = { new ServerPort("localhost", Port, ServerCredentials.Insecure) } }; server.Start(); Console.WriteLine("RouteGuide server listening on port " + Port); Console.WriteLine("Press any key to stop the server..."); Console.ReadKey(); server.ShutdownAsync().Wait(); } } }
如您所见,我们使用Grpc.Core.Server
类构建和启动我们的服务器。为此,我们:
- 创建一个实例
Grpc.Core.Server
。 - 创建我们的服务实现类的实例
RouteGuideImpl
。 - 通过将其服务定义添加到
Services
集合来注册我们的服务实现 (我们从生成的RouteGuide.BindService
方法中获取服务定义 )。 - 指定我们要用于侦听客户端请求的地址和端口。这是通过添加
ServerPort
到Ports
集合来完成的。 - 调用
Start
服务器实例为我们的服务启动RPC服务器。
- 创建客户端
// 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 Grpc.Core; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Routeguide { class Program { /// <summary> /// Sample client code that makes gRPC calls to the server. /// </summary> public class RouteGuideClient { readonly RouteGuide.RouteGuideClient client; public RouteGuideClient(RouteGuide.RouteGuideClient client) { this.client = client; } /// <summary> /// Blocking unary call example. Calls GetFeature and prints the response. /// </summary> public void GetFeature(int lat, int lon) { try { Log("*** GetFeature: lat={0} lon={1}", lat, lon); Point request = new Point { Latitude = lat, Longitude = lon }; Feature feature = client.GetFeature(request); if (feature.Exists()) { Log("Found feature called "{0}" at {1}, {2}", feature.Name, feature.Location.GetLatitude(), feature.Location.GetLongitude()); } else { Log("Found no feature at {0}, {1}", feature.Location.GetLatitude(), feature.Location.GetLongitude()); } } catch (RpcException e) { Log("RPC failed " + e); throw; } } /// <summary> /// Server-streaming example. Calls listFeatures with a rectangle of interest. Prints each response feature as it arrives. /// </summary> public async Task ListFeatures(int lowLat, int lowLon, int hiLat, int hiLon) { try { Log("*** ListFeatures: lowLat={0} lowLon={1} hiLat={2} hiLon={3}", lowLat, lowLon, hiLat, hiLon); Rectangle request = new Rectangle { Lo = new Point { Latitude = lowLat, Longitude = lowLon }, Hi = new Point { Latitude = hiLat, Longitude = hiLon } }; using (var call = client.ListFeatures(request)) { var responseStream = call.ResponseStream; StringBuilder responseLog = new StringBuilder("Result: "); while (await responseStream.MoveNext()) { Feature feature = responseStream.Current; responseLog.Append(feature.ToString()); } Log(responseLog.ToString()); } } catch (RpcException e) { Log("RPC failed " + e); throw; } } /// <summary> /// Client-streaming example. Sends numPoints randomly chosen points from features /// with a variable delay in between. Prints the statistics when they are sent from the server. /// </summary> public async Task RecordRoute(List<Feature> features, int numPoints) { try { Log("*** RecordRoute"); using (var call = client.RecordRoute()) { // Send numPoints points randomly selected from the features list. StringBuilder numMsg = new StringBuilder(); Random rand = new Random(); for (int i = 0; i < numPoints; ++i) { int index = rand.Next(features.Count); Point point = features[index].Location; Log("Visiting point {0}, {1}", point.GetLatitude(), point.GetLongitude()); await call.RequestStream.WriteAsync(point); // A bit of delay before sending the next one. await Task.Delay(rand.Next(1000) + 500); } await call.RequestStream.CompleteAsync(); RouteSummary summary = await call.ResponseAsync; Log("Finished trip with {0} points. Passed {1} features. " + "Travelled {2} meters. It took {3} seconds.", summary.PointCount, summary.FeatureCount, summary.Distance, summary.ElapsedTime); Log("Finished RecordRoute"); } } catch (RpcException e) { Log("RPC failed", e); throw; } } /// <summary> /// Bi-directional streaming example. Send some chat messages, and print any /// chat messages that are sent from the server. /// </summary> public async Task RouteChat() { try { Log("*** RouteChat"); var requests = new List<RouteNote> { NewNote("First message", 0, 0), NewNote("Second message", 0, 1), NewNote("Third message", 1, 0), NewNote("Fourth message", 0, 0) }; using (var call = client.RouteChat()) { var responseReaderTask = Task.Run(async () => { while (await call.ResponseStream.MoveNext()) { var note = call.ResponseStream.Current; Log("Got message "{0}" at {1}, {2}", note.Message, note.Location.Latitude, note.Location.Longitude); } }); foreach (RouteNote request in requests) { Log("Sending message "{0}" at {1}, {2}", request.Message, request.Location.Latitude, request.Location.Longitude); await call.RequestStream.WriteAsync(request); } await call.RequestStream.CompleteAsync(); await responseReaderTask; Log("Finished RouteChat"); } } catch (RpcException e) { Log("RPC failed", e); throw; } } private void Log(string s, params object[] args) { Console.WriteLine(string.Format(s, args)); } private void Log(string s) { Console.WriteLine(s); } private RouteNote NewNote(string message, int lat, int lon) { return new RouteNote { Message = message, Location = new Point { Latitude = lat, Longitude = lon } }; } } static void Main(string[] args) { var channel = new Channel("127.0.0.1:50052", ChannelCredentials.Insecure); var client = new RouteGuideClient(new RouteGuide.RouteGuideClient(channel)); // Looking for a valid feature client.GetFeature(409146138, -746188906); // Feature missing. client.GetFeature(0, 0); // Looking for features between 40, -75 and 42, -73. client.ListFeatures(400000000, -750000000, 420000000, -730000000).Wait(); // Record a few randomly selected points from the features file. client.RecordRoute(RouteGuideUtil.ParseFeatures(RouteGuideUtil.DefaultFeaturesFile), 10).Wait(); // Send and receive some notes. client.RouteChat().Wait(); channel.ShutdownAsync().Wait(); Console.WriteLine("Press any key to exit..."); Console.ReadKey(); } } }
- 最后可以在Visual Studio中启动项目RouteGuideClient和RouteGuideServer