• 在C#中简单使用gRPC


    一、引言

      本文采用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.ToolsNuGet包与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
    View 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
    View Code
    • 创建服务器
    1. 通过继承从我们的服务定义生成的基类来实现服务功能:执行我们服务的实际“工作”。
    2. 运行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;
            }
        }
    }
    View Code
    // 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();
            }
        }
    }
    View Code

      如您所见,我们使用Grpc.Core.Server类构建和启动我们的服务器。为此,我们:

    1. 创建一个实例Grpc.Core.Server
    2. 创建我们的服务实现类的实例RouteGuideImpl
    3. 通过将其服务定义添加到Services集合来注册我们的服务实现 (我们从生成的RouteGuide.BindService方法中获取服务定义 )。
    4. 指定我们要用于侦听客户端请求的地址和端口。这是通过添加ServerPortPorts集合来完成的
    5. 调用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();
            }
        }
    }
    View Code
    •  最后可以在Visual Studio中启动项目RouteGuideClient和RouteGuideServer
  • 相关阅读:
    Linux命令-压缩解压命令:gzip、gunzip
    Linux命令-用户管理命令:useradd,passwd,who,w
    Linux命令-帮助命令:help
    Linux命令-帮助命令:whatis,apropos
    Linux命令-帮助命令:man
    Linux命令-文件搜索命令:grep
    Linux命令-文件搜索命令:whereis
    Linux命令-文件搜索命令:which
    Linux命令-文件搜索命令:locate
    Linux命令-文件搜索命令:find
  • 原文地址:https://www.cnblogs.com/jesen1315/p/11389936.html
Copyright © 2020-2023  润新知