├── LICENSE
├── README.md
└── src
├── GrpcLibrary
├── GrpcLibrary.csproj
├── Helloworld.cs
├── HelloworldGrpc.cs
├── NullRequest.cs
└── NullRequestGrpc.cs
├── GrpcService
├── GrpcService.csproj
└── Program.cs
├── LB1
├── LB1.csproj
├── LB1.csproj.user
├── Program.cs
├── Properties
│ └── launchSettings.json
└── Startup.cs
├── LB2
├── LB2.csproj
├── LB2.csproj.user
├── Program.cs
├── Properties
│ └── launchSettings.json
└── Startup.cs
├── Ocelot.GrpcHttpGateway.sln
├── Ocelot.GrpcHttpGateway
├── Configuration
│ ├── GrpcGatewayExtensions.cs
│ └── GrpcPipelineConfigurationExtensions.cs
├── GrpcHttpMiddleware.cs
├── GrpcHttpMiddlewareExtensions.cs
├── GrpcRequest
│ ├── GrpcClient
│ │ ├── ArgsParser.cs
│ │ ├── GrpcChannelFactory.cs
│ │ ├── GrpcClient.cs
│ │ ├── GrpcMethod.cs
│ │ └── IGrpcChannelFactory.cs
│ ├── GrpcHttpContent.cs
│ ├── GrpcRequest.cs
│ ├── GrpcRequestBuilder.cs
│ ├── IGrpcRequestBuilder.cs
│ └── UnknownError.cs
├── Ocelot.GrpcHttpGateway.csproj
├── Ocelot.GrpcHttpGateway.csproj.user
└── ServiceDescriptor
│ ├── GrpcServiceDescriptor.cs
│ └── IGrpcServiceDescriptor.cs
└── WebGateway
├── DefaultServiceDescriptor.cs
├── Program.cs
├── Properties
├── PublishProfiles
│ ├── FolderProfile.pubxml
│ └── FolderProfile.pubxml.user
└── launchSettings.json
├── Startup.cs
├── WebGateway.csproj
├── WebGateway.csproj.user
├── appsettings.json
└── ocelot.json
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 yuezhishun
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Ocelot.GrpcHttpGateway
2 | grpc service gateway used ocelot
3 |
--------------------------------------------------------------------------------
/src/GrpcLibrary/GrpcLibrary.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/GrpcLibrary/Helloworld.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Generated by the protocol buffer compiler. DO NOT EDIT!
3 | // source: helloworld.proto
4 | //
5 | #pragma warning disable 1591, 0612, 3021
6 | #region Designer generated code
7 |
8 | using pb = global::Google.Protobuf;
9 | using pbc = global::Google.Protobuf.Collections;
10 | using pbr = global::Google.Protobuf.Reflection;
11 | using scg = global::System.Collections.Generic;
12 | namespace GrpcServerImpl {
13 |
14 | /// Holder for reflection information generated from helloworld.proto
15 | public static partial class HelloworldReflection {
16 |
17 | #region Descriptor
18 | /// File descriptor for helloworld.proto
19 | public static pbr::FileDescriptor Descriptor {
20 | get { return descriptor; }
21 | }
22 | private static pbr::FileDescriptor descriptor;
23 |
24 | static HelloworldReflection() {
25 | byte[] descriptorData = global::System.Convert.FromBase64String(
26 | string.Concat(
27 | "ChBoZWxsb3dvcmxkLnByb3RvEgpHcnBjU2VydmVyIhwKDEhlbGxvUmVxdWVz",
28 | "dBIMCgRuYW1lGAEgASgJIh0KCkhlbGxvUmVwbHkSDwoHbWVzc2FnZRgBIAEo",
29 | "CTJLCglIZWxsb0dycGMSPgoIU2F5SGVsbG8SGC5HcnBjU2VydmVyLkhlbGxv",
30 | "UmVxdWVzdBoWLkdycGNTZXJ2ZXIuSGVsbG9SZXBseSIAQhGqAg5HcnBjU2Vy",
31 | "dmVySW1wbGIGcHJvdG8z"));
32 | descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
33 | new pbr::FileDescriptor[] { },
34 | new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
35 | new pbr::GeneratedClrTypeInfo(typeof(global::GrpcServerImpl.HelloRequest), global::GrpcServerImpl.HelloRequest.Parser, new[]{ "Name" }, null, null, null),
36 | new pbr::GeneratedClrTypeInfo(typeof(global::GrpcServerImpl.HelloReply), global::GrpcServerImpl.HelloReply.Parser, new[]{ "Message" }, null, null, null)
37 | }));
38 | }
39 | #endregion
40 |
41 | }
42 | #region Messages
43 | ///
44 | /// The request message containing the user's name.
45 | ///
46 | public sealed partial class HelloRequest : pb::IMessage {
47 | private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new HelloRequest());
48 | private pb::UnknownFieldSet _unknownFields;
49 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
50 | public static pb::MessageParser Parser { get { return _parser; } }
51 |
52 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
53 | public static pbr::MessageDescriptor Descriptor {
54 | get { return global::GrpcServerImpl.HelloworldReflection.Descriptor.MessageTypes[0]; }
55 | }
56 |
57 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
58 | pbr::MessageDescriptor pb::IMessage.Descriptor {
59 | get { return Descriptor; }
60 | }
61 |
62 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
63 | public HelloRequest() {
64 | OnConstruction();
65 | }
66 |
67 | partial void OnConstruction();
68 |
69 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
70 | public HelloRequest(HelloRequest other) : this() {
71 | name_ = other.name_;
72 | _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
73 | }
74 |
75 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
76 | public HelloRequest Clone() {
77 | return new HelloRequest(this);
78 | }
79 |
80 | /// Field number for the "name" field.
81 | public const int NameFieldNumber = 1;
82 | private string name_ = "";
83 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
84 | public string Name {
85 | get { return name_; }
86 | set {
87 | name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
88 | }
89 | }
90 |
91 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
92 | public override bool Equals(object other) {
93 | return Equals(other as HelloRequest);
94 | }
95 |
96 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
97 | public bool Equals(HelloRequest other) {
98 | if (ReferenceEquals(other, null)) {
99 | return false;
100 | }
101 | if (ReferenceEquals(other, this)) {
102 | return true;
103 | }
104 | if (Name != other.Name) return false;
105 | return Equals(_unknownFields, other._unknownFields);
106 | }
107 |
108 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
109 | public override int GetHashCode() {
110 | int hash = 1;
111 | if (Name.Length != 0) hash ^= Name.GetHashCode();
112 | if (_unknownFields != null) {
113 | hash ^= _unknownFields.GetHashCode();
114 | }
115 | return hash;
116 | }
117 |
118 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
119 | public override string ToString() {
120 | return pb::JsonFormatter.ToDiagnosticString(this);
121 | }
122 |
123 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
124 | public void WriteTo(pb::CodedOutputStream output) {
125 | if (Name.Length != 0) {
126 | output.WriteRawTag(10);
127 | output.WriteString(Name);
128 | }
129 | if (_unknownFields != null) {
130 | _unknownFields.WriteTo(output);
131 | }
132 | }
133 |
134 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
135 | public int CalculateSize() {
136 | int size = 0;
137 | if (Name.Length != 0) {
138 | size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
139 | }
140 | if (_unknownFields != null) {
141 | size += _unknownFields.CalculateSize();
142 | }
143 | return size;
144 | }
145 |
146 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
147 | public void MergeFrom(HelloRequest other) {
148 | if (other == null) {
149 | return;
150 | }
151 | if (other.Name.Length != 0) {
152 | Name = other.Name;
153 | }
154 | _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
155 | }
156 |
157 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
158 | public void MergeFrom(pb::CodedInputStream input) {
159 | uint tag;
160 | while ((tag = input.ReadTag()) != 0) {
161 | switch(tag) {
162 | default:
163 | _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
164 | break;
165 | case 10: {
166 | Name = input.ReadString();
167 | break;
168 | }
169 | }
170 | }
171 | }
172 |
173 | }
174 |
175 | ///
176 | /// The response message containing the greetings
177 | ///
178 | public sealed partial class HelloReply : pb::IMessage {
179 | private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new HelloReply());
180 | private pb::UnknownFieldSet _unknownFields;
181 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
182 | public static pb::MessageParser Parser { get { return _parser; } }
183 |
184 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
185 | public static pbr::MessageDescriptor Descriptor {
186 | get { return global::GrpcServerImpl.HelloworldReflection.Descriptor.MessageTypes[1]; }
187 | }
188 |
189 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
190 | pbr::MessageDescriptor pb::IMessage.Descriptor {
191 | get { return Descriptor; }
192 | }
193 |
194 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
195 | public HelloReply() {
196 | OnConstruction();
197 | }
198 |
199 | partial void OnConstruction();
200 |
201 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
202 | public HelloReply(HelloReply other) : this() {
203 | message_ = other.message_;
204 | _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
205 | }
206 |
207 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
208 | public HelloReply Clone() {
209 | return new HelloReply(this);
210 | }
211 |
212 | /// Field number for the "message" field.
213 | public const int MessageFieldNumber = 1;
214 | private string message_ = "";
215 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
216 | public string Message {
217 | get { return message_; }
218 | set {
219 | message_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
220 | }
221 | }
222 |
223 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
224 | public override bool Equals(object other) {
225 | return Equals(other as HelloReply);
226 | }
227 |
228 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
229 | public bool Equals(HelloReply other) {
230 | if (ReferenceEquals(other, null)) {
231 | return false;
232 | }
233 | if (ReferenceEquals(other, this)) {
234 | return true;
235 | }
236 | if (Message != other.Message) return false;
237 | return Equals(_unknownFields, other._unknownFields);
238 | }
239 |
240 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
241 | public override int GetHashCode() {
242 | int hash = 1;
243 | if (Message.Length != 0) hash ^= Message.GetHashCode();
244 | if (_unknownFields != null) {
245 | hash ^= _unknownFields.GetHashCode();
246 | }
247 | return hash;
248 | }
249 |
250 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
251 | public override string ToString() {
252 | return pb::JsonFormatter.ToDiagnosticString(this);
253 | }
254 |
255 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
256 | public void WriteTo(pb::CodedOutputStream output) {
257 | if (Message.Length != 0) {
258 | output.WriteRawTag(10);
259 | output.WriteString(Message);
260 | }
261 | if (_unknownFields != null) {
262 | _unknownFields.WriteTo(output);
263 | }
264 | }
265 |
266 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
267 | public int CalculateSize() {
268 | int size = 0;
269 | if (Message.Length != 0) {
270 | size += 1 + pb::CodedOutputStream.ComputeStringSize(Message);
271 | }
272 | if (_unknownFields != null) {
273 | size += _unknownFields.CalculateSize();
274 | }
275 | return size;
276 | }
277 |
278 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
279 | public void MergeFrom(HelloReply other) {
280 | if (other == null) {
281 | return;
282 | }
283 | if (other.Message.Length != 0) {
284 | Message = other.Message;
285 | }
286 | _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
287 | }
288 |
289 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
290 | public void MergeFrom(pb::CodedInputStream input) {
291 | uint tag;
292 | while ((tag = input.ReadTag()) != 0) {
293 | switch(tag) {
294 | default:
295 | _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
296 | break;
297 | case 10: {
298 | Message = input.ReadString();
299 | break;
300 | }
301 | }
302 | }
303 | }
304 |
305 | }
306 |
307 | #endregion
308 |
309 | }
310 |
311 | #endregion Designer generated code
312 |
--------------------------------------------------------------------------------
/src/GrpcLibrary/HelloworldGrpc.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Generated by the protocol buffer compiler. DO NOT EDIT!
3 | // source: helloworld.proto
4 | //
5 | #pragma warning disable 0414, 1591
6 | #region Designer generated code
7 |
8 | using grpc = global::Grpc.Core;
9 |
10 | namespace GrpcServerImpl {
11 | ///
12 | /// The service definition.
13 | ///
14 | public static partial class HelloGrpc
15 | {
16 | static readonly string __ServiceName = "GrpcServer.HelloGrpc";
17 |
18 | static readonly grpc::Marshaller __Marshaller_GrpcServer_HelloRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::GrpcServerImpl.HelloRequest.Parser.ParseFrom);
19 | static readonly grpc::Marshaller __Marshaller_GrpcServer_HelloReply = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::GrpcServerImpl.HelloReply.Parser.ParseFrom);
20 |
21 | static readonly grpc::Method __Method_SayHello = new grpc::Method(
22 | grpc::MethodType.Unary,
23 | __ServiceName,
24 | "SayHello",
25 | __Marshaller_GrpcServer_HelloRequest,
26 | __Marshaller_GrpcServer_HelloReply);
27 |
28 | /// Service descriptor
29 | public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
30 | {
31 | get { return global::GrpcServerImpl.HelloworldReflection.Descriptor.Services[0]; }
32 | }
33 |
34 | /// Base class for server-side implementations of HelloGrpc
35 | public abstract partial class HelloGrpcBase
36 | {
37 | ///
38 | /// Sends a greeting
39 | ///
40 | /// The request received from the client.
41 | /// The context of the server-side call handler being invoked.
42 | /// The response to send back to the client (wrapped by a task).
43 | public virtual global::System.Threading.Tasks.Task SayHello(global::GrpcServerImpl.HelloRequest request, grpc::ServerCallContext context)
44 | {
45 | throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
46 | }
47 |
48 | }
49 |
50 | /// Client for HelloGrpc
51 | public partial class HelloGrpcClient : grpc::ClientBase
52 | {
53 | /// Creates a new client for HelloGrpc
54 | /// The channel to use to make remote calls.
55 | public HelloGrpcClient(grpc::Channel channel) : base(channel)
56 | {
57 | }
58 | /// Creates a new client for HelloGrpc that uses a custom CallInvoker.
59 | /// The callInvoker to use to make remote calls.
60 | public HelloGrpcClient(grpc::CallInvoker callInvoker) : base(callInvoker)
61 | {
62 | }
63 | /// Protected parameterless constructor to allow creation of test doubles.
64 | protected HelloGrpcClient() : base()
65 | {
66 | }
67 | /// Protected constructor to allow creation of configured clients.
68 | /// The client configuration.
69 | protected HelloGrpcClient(ClientBaseConfiguration configuration) : base(configuration)
70 | {
71 | }
72 |
73 | ///
74 | /// Sends a greeting
75 | ///
76 | /// The request to send to the server.
77 | /// The initial metadata to send with the call. This parameter is optional.
78 | /// An optional deadline for the call. The call will be cancelled if deadline is hit.
79 | /// An optional token for canceling the call.
80 | /// The response received from the server.
81 | public virtual global::GrpcServerImpl.HelloReply SayHello(global::GrpcServerImpl.HelloRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
82 | {
83 | return SayHello(request, new grpc::CallOptions(headers, deadline, cancellationToken));
84 | }
85 | ///
86 | /// Sends a greeting
87 | ///
88 | /// The request to send to the server.
89 | /// The options for the call.
90 | /// The response received from the server.
91 | public virtual global::GrpcServerImpl.HelloReply SayHello(global::GrpcServerImpl.HelloRequest request, grpc::CallOptions options)
92 | {
93 | return CallInvoker.BlockingUnaryCall(__Method_SayHello, null, options, request);
94 | }
95 | ///
96 | /// Sends a greeting
97 | ///
98 | /// The request to send to the server.
99 | /// The initial metadata to send with the call. This parameter is optional.
100 | /// An optional deadline for the call. The call will be cancelled if deadline is hit.
101 | /// An optional token for canceling the call.
102 | /// The call object.
103 | public virtual grpc::AsyncUnaryCall SayHelloAsync(global::GrpcServerImpl.HelloRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
104 | {
105 | return SayHelloAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
106 | }
107 | ///
108 | /// Sends a greeting
109 | ///
110 | /// The request to send to the server.
111 | /// The options for the call.
112 | /// The call object.
113 | public virtual grpc::AsyncUnaryCall SayHelloAsync(global::GrpcServerImpl.HelloRequest request, grpc::CallOptions options)
114 | {
115 | return CallInvoker.AsyncUnaryCall(__Method_SayHello, null, options, request);
116 | }
117 | /// Creates a new instance of client from given ClientBaseConfiguration.
118 | protected override HelloGrpcClient NewInstance(ClientBaseConfiguration configuration)
119 | {
120 | return new HelloGrpcClient(configuration);
121 | }
122 | }
123 |
124 | /// Creates service definition that can be registered with a server
125 | /// An object implementing the server-side handling logic.
126 | public static grpc::ServerServiceDefinition BindService(HelloGrpcBase serviceImpl)
127 | {
128 | return grpc::ServerServiceDefinition.CreateBuilder()
129 | .AddMethod(__Method_SayHello, serviceImpl.SayHello).Build();
130 | }
131 |
132 | }
133 | }
134 | #endregion
135 |
--------------------------------------------------------------------------------
/src/GrpcLibrary/NullRequest.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Generated by the protocol buffer compiler. DO NOT EDIT!
3 | // source: NullRequest.proto
4 | //
5 | #pragma warning disable 1591, 0612, 3021
6 | #region Designer generated code
7 |
8 | using pb = global::Google.Protobuf;
9 | using pbc = global::Google.Protobuf.Collections;
10 | using pbr = global::Google.Protobuf.Reflection;
11 | using scg = global::System.Collections.Generic;
12 | namespace GrpcServerImpl {
13 |
14 | /// Holder for reflection information generated from NullRequest.proto
15 | public static partial class NullRequestReflection {
16 |
17 | #region Descriptor
18 | /// File descriptor for NullRequest.proto
19 | public static pbr::FileDescriptor Descriptor {
20 | get { return descriptor; }
21 | }
22 | private static pbr::FileDescriptor descriptor;
23 |
24 | static NullRequestReflection() {
25 | byte[] descriptorData = global::System.Convert.FromBase64String(
26 | string.Concat(
27 | "ChFOdWxsUmVxdWVzdC5wcm90bxIKR3JwY1NlcnZlciINCgtOdWxsUmVxdWVz",
28 | "dCILCglOdWxsUmVwbHkyTQoNSGVsbG9OdWxsR3JwYxI8CghTYXlIZWxsbxIX",
29 | "LkdycGNTZXJ2ZXIuTnVsbFJlcXVlc3QaFS5HcnBjU2VydmVyLk51bGxSZXBs",
30 | "eSIAQhGqAg5HcnBjU2VydmVySW1wbGIGcHJvdG8z"));
31 | descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
32 | new pbr::FileDescriptor[] { },
33 | new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
34 | new pbr::GeneratedClrTypeInfo(typeof(global::GrpcServerImpl.NullRequest), global::GrpcServerImpl.NullRequest.Parser, null, null, null, null),
35 | new pbr::GeneratedClrTypeInfo(typeof(global::GrpcServerImpl.NullReply), global::GrpcServerImpl.NullReply.Parser, null, null, null, null)
36 | }));
37 | }
38 | #endregion
39 |
40 | }
41 | #region Messages
42 | ///
43 | /// The request message containing the user's name.
44 | ///
45 | public sealed partial class NullRequest : pb::IMessage {
46 | private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NullRequest());
47 | private pb::UnknownFieldSet _unknownFields;
48 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
49 | public static pb::MessageParser Parser { get { return _parser; } }
50 |
51 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
52 | public static pbr::MessageDescriptor Descriptor {
53 | get { return global::GrpcServerImpl.NullRequestReflection.Descriptor.MessageTypes[0]; }
54 | }
55 |
56 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
57 | pbr::MessageDescriptor pb::IMessage.Descriptor {
58 | get { return Descriptor; }
59 | }
60 |
61 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
62 | public NullRequest() {
63 | OnConstruction();
64 | }
65 |
66 | partial void OnConstruction();
67 |
68 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
69 | public NullRequest(NullRequest other) : this() {
70 | _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
71 | }
72 |
73 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
74 | public NullRequest Clone() {
75 | return new NullRequest(this);
76 | }
77 |
78 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
79 | public override bool Equals(object other) {
80 | return Equals(other as NullRequest);
81 | }
82 |
83 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
84 | public bool Equals(NullRequest other) {
85 | if (ReferenceEquals(other, null)) {
86 | return false;
87 | }
88 | if (ReferenceEquals(other, this)) {
89 | return true;
90 | }
91 | return Equals(_unknownFields, other._unknownFields);
92 | }
93 |
94 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
95 | public override int GetHashCode() {
96 | int hash = 1;
97 | if (_unknownFields != null) {
98 | hash ^= _unknownFields.GetHashCode();
99 | }
100 | return hash;
101 | }
102 |
103 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
104 | public override string ToString() {
105 | return pb::JsonFormatter.ToDiagnosticString(this);
106 | }
107 |
108 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
109 | public void WriteTo(pb::CodedOutputStream output) {
110 | if (_unknownFields != null) {
111 | _unknownFields.WriteTo(output);
112 | }
113 | }
114 |
115 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
116 | public int CalculateSize() {
117 | int size = 0;
118 | if (_unknownFields != null) {
119 | size += _unknownFields.CalculateSize();
120 | }
121 | return size;
122 | }
123 |
124 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
125 | public void MergeFrom(NullRequest other) {
126 | if (other == null) {
127 | return;
128 | }
129 | _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
130 | }
131 |
132 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
133 | public void MergeFrom(pb::CodedInputStream input) {
134 | uint tag;
135 | while ((tag = input.ReadTag()) != 0) {
136 | switch(tag) {
137 | default:
138 | _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
139 | break;
140 | }
141 | }
142 | }
143 |
144 | }
145 |
146 | ///
147 | /// The response message containing the greetings
148 | ///
149 | public sealed partial class NullReply : pb::IMessage {
150 | private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NullReply());
151 | private pb::UnknownFieldSet _unknownFields;
152 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
153 | public static pb::MessageParser Parser { get { return _parser; } }
154 |
155 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
156 | public static pbr::MessageDescriptor Descriptor {
157 | get { return global::GrpcServerImpl.NullRequestReflection.Descriptor.MessageTypes[1]; }
158 | }
159 |
160 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
161 | pbr::MessageDescriptor pb::IMessage.Descriptor {
162 | get { return Descriptor; }
163 | }
164 |
165 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
166 | public NullReply() {
167 | OnConstruction();
168 | }
169 |
170 | partial void OnConstruction();
171 |
172 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
173 | public NullReply(NullReply other) : this() {
174 | _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
175 | }
176 |
177 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
178 | public NullReply Clone() {
179 | return new NullReply(this);
180 | }
181 |
182 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
183 | public override bool Equals(object other) {
184 | return Equals(other as NullReply);
185 | }
186 |
187 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
188 | public bool Equals(NullReply other) {
189 | if (ReferenceEquals(other, null)) {
190 | return false;
191 | }
192 | if (ReferenceEquals(other, this)) {
193 | return true;
194 | }
195 | return Equals(_unknownFields, other._unknownFields);
196 | }
197 |
198 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
199 | public override int GetHashCode() {
200 | int hash = 1;
201 | if (_unknownFields != null) {
202 | hash ^= _unknownFields.GetHashCode();
203 | }
204 | return hash;
205 | }
206 |
207 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
208 | public override string ToString() {
209 | return pb::JsonFormatter.ToDiagnosticString(this);
210 | }
211 |
212 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
213 | public void WriteTo(pb::CodedOutputStream output) {
214 | if (_unknownFields != null) {
215 | _unknownFields.WriteTo(output);
216 | }
217 | }
218 |
219 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
220 | public int CalculateSize() {
221 | int size = 0;
222 | if (_unknownFields != null) {
223 | size += _unknownFields.CalculateSize();
224 | }
225 | return size;
226 | }
227 |
228 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
229 | public void MergeFrom(NullReply other) {
230 | if (other == null) {
231 | return;
232 | }
233 | _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
234 | }
235 |
236 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
237 | public void MergeFrom(pb::CodedInputStream input) {
238 | uint tag;
239 | while ((tag = input.ReadTag()) != 0) {
240 | switch(tag) {
241 | default:
242 | _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
243 | break;
244 | }
245 | }
246 | }
247 |
248 | }
249 |
250 | #endregion
251 |
252 | }
253 |
254 | #endregion Designer generated code
255 |
--------------------------------------------------------------------------------
/src/GrpcLibrary/NullRequestGrpc.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Generated by the protocol buffer compiler. DO NOT EDIT!
3 | // source: NullRequest.proto
4 | //
5 | #pragma warning disable 0414, 1591
6 | #region Designer generated code
7 |
8 | using grpc = global::Grpc.Core;
9 |
10 | namespace GrpcServerImpl {
11 | ///
12 | /// The service definition.
13 | ///
14 | public static partial class HelloNullGrpc
15 | {
16 | static readonly string __ServiceName = "GrpcServer.HelloNullGrpc";
17 |
18 | static readonly grpc::Marshaller __Marshaller_GrpcServer_NullRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::GrpcServerImpl.NullRequest.Parser.ParseFrom);
19 | static readonly grpc::Marshaller __Marshaller_GrpcServer_NullReply = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::GrpcServerImpl.NullReply.Parser.ParseFrom);
20 |
21 | static readonly grpc::Method __Method_SayHello = new grpc::Method(
22 | grpc::MethodType.Unary,
23 | __ServiceName,
24 | "SayHello",
25 | __Marshaller_GrpcServer_NullRequest,
26 | __Marshaller_GrpcServer_NullReply);
27 |
28 | /// Service descriptor
29 | public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
30 | {
31 | get { return global::GrpcServerImpl.NullRequestReflection.Descriptor.Services[0]; }
32 | }
33 |
34 | /// Base class for server-side implementations of HelloNullGrpc
35 | public abstract partial class HelloNullGrpcBase
36 | {
37 | ///
38 | /// Sends a greeting
39 | ///
40 | /// The request received from the client.
41 | /// The context of the server-side call handler being invoked.
42 | /// The response to send back to the client (wrapped by a task).
43 | public virtual global::System.Threading.Tasks.Task SayHello(global::GrpcServerImpl.NullRequest request, grpc::ServerCallContext context)
44 | {
45 | throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
46 | }
47 |
48 | }
49 |
50 | /// Client for HelloNullGrpc
51 | public partial class HelloNullGrpcClient : grpc::ClientBase
52 | {
53 | /// Creates a new client for HelloNullGrpc
54 | /// The channel to use to make remote calls.
55 | public HelloNullGrpcClient(grpc::Channel channel) : base(channel)
56 | {
57 | }
58 | /// Creates a new client for HelloNullGrpc that uses a custom CallInvoker.
59 | /// The callInvoker to use to make remote calls.
60 | public HelloNullGrpcClient(grpc::CallInvoker callInvoker) : base(callInvoker)
61 | {
62 | }
63 | /// Protected parameterless constructor to allow creation of test doubles.
64 | protected HelloNullGrpcClient() : base()
65 | {
66 | }
67 | /// Protected constructor to allow creation of configured clients.
68 | /// The client configuration.
69 | protected HelloNullGrpcClient(ClientBaseConfiguration configuration) : base(configuration)
70 | {
71 | }
72 |
73 | ///
74 | /// Sends a greeting
75 | ///
76 | /// The request to send to the server.
77 | /// The initial metadata to send with the call. This parameter is optional.
78 | /// An optional deadline for the call. The call will be cancelled if deadline is hit.
79 | /// An optional token for canceling the call.
80 | /// The response received from the server.
81 | public virtual global::GrpcServerImpl.NullReply SayHello(global::GrpcServerImpl.NullRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
82 | {
83 | return SayHello(request, new grpc::CallOptions(headers, deadline, cancellationToken));
84 | }
85 | ///
86 | /// Sends a greeting
87 | ///
88 | /// The request to send to the server.
89 | /// The options for the call.
90 | /// The response received from the server.
91 | public virtual global::GrpcServerImpl.NullReply SayHello(global::GrpcServerImpl.NullRequest request, grpc::CallOptions options)
92 | {
93 | return CallInvoker.BlockingUnaryCall(__Method_SayHello, null, options, request);
94 | }
95 | ///
96 | /// Sends a greeting
97 | ///
98 | /// The request to send to the server.
99 | /// The initial metadata to send with the call. This parameter is optional.
100 | /// An optional deadline for the call. The call will be cancelled if deadline is hit.
101 | /// An optional token for canceling the call.
102 | /// The call object.
103 | public virtual grpc::AsyncUnaryCall SayHelloAsync(global::GrpcServerImpl.NullRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
104 | {
105 | return SayHelloAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
106 | }
107 | ///
108 | /// Sends a greeting
109 | ///
110 | /// The request to send to the server.
111 | /// The options for the call.
112 | /// The call object.
113 | public virtual grpc::AsyncUnaryCall SayHelloAsync(global::GrpcServerImpl.NullRequest request, grpc::CallOptions options)
114 | {
115 | return CallInvoker.AsyncUnaryCall(__Method_SayHello, null, options, request);
116 | }
117 | /// Creates a new instance of client from given ClientBaseConfiguration.
118 | protected override HelloNullGrpcClient NewInstance(ClientBaseConfiguration configuration)
119 | {
120 | return new HelloNullGrpcClient(configuration);
121 | }
122 | }
123 |
124 | /// Creates service definition that can be registered with a server
125 | /// An object implementing the server-side handling logic.
126 | public static grpc::ServerServiceDefinition BindService(HelloNullGrpcBase serviceImpl)
127 | {
128 | return grpc::ServerServiceDefinition.CreateBuilder()
129 | .AddMethod(__Method_SayHello, serviceImpl.SayHello).Build();
130 | }
131 |
132 | }
133 | }
134 | #endregion
135 |
--------------------------------------------------------------------------------
/src/GrpcService/GrpcService.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp2.1
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/GrpcService/Program.cs:
--------------------------------------------------------------------------------
1 | using Grpc.Core;
2 | using GrpcServerImpl;
3 | using System;
4 | using System.Threading.Tasks;
5 |
6 | namespace GrpcService
7 | {
8 | class Program
9 | {
10 | static void Main(string[] args)
11 | {
12 |
13 | int port1 = 50001;
14 | int port2 = 50002;
15 | var server1 = new Server
16 | {
17 | Services = {
18 | HelloGrpc.BindService(new HelloImpl()),
19 | HelloNullGrpc.BindService(new HelloNullImpl())
20 | },
21 | Ports = { new ServerPort("localhost", port1, ServerCredentials.Insecure) }
22 | };
23 |
24 | server1.Start();
25 | Console.WriteLine($"server1 listening on port:{port1}");
26 | var server2 = new Server
27 | {
28 | Services = {
29 | HelloGrpc.BindService(new HelloImpl()),
30 | HelloNullGrpc.BindService(new HelloNullImpl())
31 | },
32 | Ports = { new ServerPort("localhost", port2, ServerCredentials.Insecure) }
33 | };
34 | server2.Start();
35 | Console.WriteLine($"server2 listening on port:{port2}");
36 |
37 | Console.ReadLine();
38 | server1.ShutdownAsync().Wait();
39 | server2.ShutdownAsync().Wait();
40 | }
41 | }
42 | class HelloImpl : HelloGrpc.HelloGrpcBase
43 | {
44 | // Server side handler of the SayHello RPC
45 | public override Task SayHello(HelloRequest request, ServerCallContext context)
46 | {
47 | return Task.FromResult(new HelloReply { Message = context.Host });
48 | }
49 | }
50 | class HelloNullImpl : HelloNullGrpc.HelloNullGrpcBase
51 | {
52 | // Server side handler of the SayHello RPC
53 | public override Task SayHello(NullRequest request, ServerCallContext context)
54 | {
55 | return Task.FromResult(new NullReply());
56 | }
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/src/LB1/LB1.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/LB1/LB1.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ProjectDebugger
5 |
6 |
7 | LB1
8 |
9 |
--------------------------------------------------------------------------------
/src/LB1/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.Extensions.Configuration;
9 | using Microsoft.Extensions.Logging;
10 |
11 | namespace LB1
12 | {
13 | public class Program
14 | {
15 | public static void Main(string[] args)
16 | {
17 | CreateWebHostBuilder(args).Build().Run();
18 | }
19 |
20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
21 | WebHost.CreateDefaultBuilder(args)
22 | .UseUrls("http://localhost:5001")
23 | .UseStartup();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/LB1/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:5001",
7 | "sslPort": 0
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "environmentVariables": {
15 | "ASPNETCORE_ENVIRONMENT": "Development"
16 | }
17 | },
18 | "LB1": {
19 | "commandName": "Project",
20 | "launchBrowser": true,
21 | "applicationUrl": "http://localhost:5001",
22 | "environmentVariables": {
23 | "ASPNETCORE_ENVIRONMENT": "Development"
24 | }
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/src/LB1/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Builder;
6 | using Microsoft.AspNetCore.Hosting;
7 | using Microsoft.AspNetCore.Http;
8 | using Microsoft.Extensions.DependencyInjection;
9 |
10 | namespace LB1
11 | {
12 | public class Startup
13 | {
14 | // This method gets called by the runtime. Use this method to add services to the container.
15 | // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
16 | public void ConfigureServices(IServiceCollection services)
17 | {
18 | }
19 |
20 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
21 | public void Configure(IApplicationBuilder app, IHostingEnvironment env)
22 | {
23 | if (env.IsDevelopment())
24 | {
25 | app.UseDeveloperExceptionPage();
26 | }
27 |
28 | app.Run(async (context) =>
29 | {
30 | await context.Response.WriteAsync($"LB1--{context.Request.Scheme}://{context.Request.Host.Value}{context.Request.Path}");
31 | });
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/LB2/LB2.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/LB2/LB2.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ProjectDebugger
5 |
6 |
7 | LB2
8 |
9 |
--------------------------------------------------------------------------------
/src/LB2/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.Extensions.Configuration;
9 | using Microsoft.Extensions.Logging;
10 |
11 | namespace LB2
12 | {
13 | public class Program
14 | {
15 | public static void Main(string[] args)
16 | {
17 | CreateWebHostBuilder(args).Build().Run();
18 | }
19 |
20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
21 | WebHost.CreateDefaultBuilder(args)
22 | .UseUrls("http://localhost:5002")
23 | .UseStartup();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/LB2/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:5002",
7 | "sslPort": 0
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "environmentVariables": {
15 | "ASPNETCORE_ENVIRONMENT": "Development"
16 | }
17 | },
18 | "LB2": {
19 | "commandName": "Project",
20 | "launchBrowser": true,
21 | "applicationUrl": "http://localhost:5002",
22 | "environmentVariables": {
23 | "ASPNETCORE_ENVIRONMENT": "Development"
24 | }
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/src/LB2/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Builder;
6 | using Microsoft.AspNetCore.Hosting;
7 | using Microsoft.AspNetCore.Http;
8 | using Microsoft.Extensions.DependencyInjection;
9 |
10 | namespace LB2
11 | {
12 | public class Startup
13 | {
14 | // This method gets called by the runtime. Use this method to add services to the container.
15 | // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
16 | public void ConfigureServices(IServiceCollection services)
17 | {
18 | }
19 |
20 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
21 | public void Configure(IApplicationBuilder app, IHostingEnvironment env)
22 | {
23 | if (env.IsDevelopment())
24 | {
25 | app.UseDeveloperExceptionPage();
26 | }
27 |
28 | app.Run(async (context) =>
29 | {
30 | await context.Response.WriteAsync($"LB2--{context.Request.Scheme}://{context.Request.Host.Value}{context.Request.Path}");
31 | });
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Ocelot.GrpcHttpGateway.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27703.2047
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebGateway", "WebGateway\WebGateway.csproj", "{6C443297-1E33-4001-8DF0-B6D014FA157F}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ocelot.GrpcHttpGateway", "Ocelot.GrpcHttpGateway\Ocelot.GrpcHttpGateway.csproj", "{4EFBE030-E33C-41D2-B7DA-BF40412BE0F5}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LB2", "LB2\LB2.csproj", "{B031BD0F-A4B5-4BF9-A91C-4BCE7C11B32E}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GrpcLibrary", "GrpcLibrary\GrpcLibrary.csproj", "{95F6A2BE-B7BA-4D93-8A8E-FAFF909D805D}"
13 | EndProject
14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GrpcService", "GrpcService\GrpcService.csproj", "{E245F6F5-A66A-46D4-9350-6152AAB0DA1B}"
15 | EndProject
16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LB1", "LB1\LB1.csproj", "{4C346307-5941-495D-B48D-CA564E51897D}"
17 | EndProject
18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebTest", "WebTest", "{EAA4D121-2849-48D0-AE06-A64B580A3A89}"
19 | EndProject
20 | Global
21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
22 | Debug|Any CPU = Debug|Any CPU
23 | Debug|x64 = Debug|x64
24 | Release|Any CPU = Release|Any CPU
25 | Release|x64 = Release|x64
26 | EndGlobalSection
27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
28 | {6C443297-1E33-4001-8DF0-B6D014FA157F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {6C443297-1E33-4001-8DF0-B6D014FA157F}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {6C443297-1E33-4001-8DF0-B6D014FA157F}.Debug|x64.ActiveCfg = Debug|Any CPU
31 | {6C443297-1E33-4001-8DF0-B6D014FA157F}.Debug|x64.Build.0 = Debug|Any CPU
32 | {6C443297-1E33-4001-8DF0-B6D014FA157F}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {6C443297-1E33-4001-8DF0-B6D014FA157F}.Release|Any CPU.Build.0 = Release|Any CPU
34 | {6C443297-1E33-4001-8DF0-B6D014FA157F}.Release|x64.ActiveCfg = Release|Any CPU
35 | {6C443297-1E33-4001-8DF0-B6D014FA157F}.Release|x64.Build.0 = Release|Any CPU
36 | {4EFBE030-E33C-41D2-B7DA-BF40412BE0F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
37 | {4EFBE030-E33C-41D2-B7DA-BF40412BE0F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
38 | {4EFBE030-E33C-41D2-B7DA-BF40412BE0F5}.Debug|x64.ActiveCfg = Debug|Any CPU
39 | {4EFBE030-E33C-41D2-B7DA-BF40412BE0F5}.Debug|x64.Build.0 = Debug|Any CPU
40 | {4EFBE030-E33C-41D2-B7DA-BF40412BE0F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
41 | {4EFBE030-E33C-41D2-B7DA-BF40412BE0F5}.Release|Any CPU.Build.0 = Release|Any CPU
42 | {4EFBE030-E33C-41D2-B7DA-BF40412BE0F5}.Release|x64.ActiveCfg = Release|Any CPU
43 | {4EFBE030-E33C-41D2-B7DA-BF40412BE0F5}.Release|x64.Build.0 = Release|Any CPU
44 | {B031BD0F-A4B5-4BF9-A91C-4BCE7C11B32E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
45 | {B031BD0F-A4B5-4BF9-A91C-4BCE7C11B32E}.Debug|Any CPU.Build.0 = Debug|Any CPU
46 | {B031BD0F-A4B5-4BF9-A91C-4BCE7C11B32E}.Debug|x64.ActiveCfg = Debug|Any CPU
47 | {B031BD0F-A4B5-4BF9-A91C-4BCE7C11B32E}.Debug|x64.Build.0 = Debug|Any CPU
48 | {B031BD0F-A4B5-4BF9-A91C-4BCE7C11B32E}.Release|Any CPU.ActiveCfg = Release|Any CPU
49 | {B031BD0F-A4B5-4BF9-A91C-4BCE7C11B32E}.Release|Any CPU.Build.0 = Release|Any CPU
50 | {B031BD0F-A4B5-4BF9-A91C-4BCE7C11B32E}.Release|x64.ActiveCfg = Release|Any CPU
51 | {B031BD0F-A4B5-4BF9-A91C-4BCE7C11B32E}.Release|x64.Build.0 = Release|Any CPU
52 | {95F6A2BE-B7BA-4D93-8A8E-FAFF909D805D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
53 | {95F6A2BE-B7BA-4D93-8A8E-FAFF909D805D}.Debug|Any CPU.Build.0 = Debug|Any CPU
54 | {95F6A2BE-B7BA-4D93-8A8E-FAFF909D805D}.Debug|x64.ActiveCfg = Debug|Any CPU
55 | {95F6A2BE-B7BA-4D93-8A8E-FAFF909D805D}.Debug|x64.Build.0 = Debug|Any CPU
56 | {95F6A2BE-B7BA-4D93-8A8E-FAFF909D805D}.Release|Any CPU.ActiveCfg = Release|Any CPU
57 | {95F6A2BE-B7BA-4D93-8A8E-FAFF909D805D}.Release|Any CPU.Build.0 = Release|Any CPU
58 | {95F6A2BE-B7BA-4D93-8A8E-FAFF909D805D}.Release|x64.ActiveCfg = Release|Any CPU
59 | {95F6A2BE-B7BA-4D93-8A8E-FAFF909D805D}.Release|x64.Build.0 = Release|Any CPU
60 | {E245F6F5-A66A-46D4-9350-6152AAB0DA1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
61 | {E245F6F5-A66A-46D4-9350-6152AAB0DA1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
62 | {E245F6F5-A66A-46D4-9350-6152AAB0DA1B}.Debug|x64.ActiveCfg = Debug|Any CPU
63 | {E245F6F5-A66A-46D4-9350-6152AAB0DA1B}.Debug|x64.Build.0 = Debug|Any CPU
64 | {E245F6F5-A66A-46D4-9350-6152AAB0DA1B}.Release|Any CPU.ActiveCfg = Release|Any CPU
65 | {E245F6F5-A66A-46D4-9350-6152AAB0DA1B}.Release|Any CPU.Build.0 = Release|Any CPU
66 | {E245F6F5-A66A-46D4-9350-6152AAB0DA1B}.Release|x64.ActiveCfg = Release|Any CPU
67 | {E245F6F5-A66A-46D4-9350-6152AAB0DA1B}.Release|x64.Build.0 = Release|Any CPU
68 | {4C346307-5941-495D-B48D-CA564E51897D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
69 | {4C346307-5941-495D-B48D-CA564E51897D}.Debug|Any CPU.Build.0 = Debug|Any CPU
70 | {4C346307-5941-495D-B48D-CA564E51897D}.Debug|x64.ActiveCfg = Debug|Any CPU
71 | {4C346307-5941-495D-B48D-CA564E51897D}.Debug|x64.Build.0 = Debug|Any CPU
72 | {4C346307-5941-495D-B48D-CA564E51897D}.Release|Any CPU.ActiveCfg = Release|Any CPU
73 | {4C346307-5941-495D-B48D-CA564E51897D}.Release|Any CPU.Build.0 = Release|Any CPU
74 | {4C346307-5941-495D-B48D-CA564E51897D}.Release|x64.ActiveCfg = Release|Any CPU
75 | {4C346307-5941-495D-B48D-CA564E51897D}.Release|x64.Build.0 = Release|Any CPU
76 | EndGlobalSection
77 | GlobalSection(SolutionProperties) = preSolution
78 | HideSolutionNode = FALSE
79 | EndGlobalSection
80 | GlobalSection(NestedProjects) = preSolution
81 | {B031BD0F-A4B5-4BF9-A91C-4BCE7C11B32E} = {EAA4D121-2849-48D0-AE06-A64B580A3A89}
82 | {4C346307-5941-495D-B48D-CA564E51897D} = {EAA4D121-2849-48D0-AE06-A64B580A3A89}
83 | EndGlobalSection
84 | GlobalSection(ExtensibilityGlobals) = postSolution
85 | SolutionGuid = {F5E7ED41-D33A-4368-AF8C-0B0EAA0857AD}
86 | EndGlobalSection
87 | EndGlobal
88 |
--------------------------------------------------------------------------------
/src/Ocelot.GrpcHttpGateway/Configuration/GrpcGatewayExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using Microsoft.Extensions.DependencyInjection.Extensions;
3 | using Ocelot.DependencyInjection;
4 |
5 | namespace Ocelot.GrpcHttpGateway
6 | {
7 | public static class GrpcGatewayExtensions
8 | {
9 | public static IOcelotBuilder AddGrpcHttpGateway(this IOcelotBuilder builder)
10 | {
11 | builder.Services.AddGrpcHttpGateway();
12 | return builder;
13 | }
14 |
15 | private static IServiceCollection AddGrpcHttpGateway(this IServiceCollection services)
16 | {
17 | services.TryAddSingleton();
18 | services.TryAddSingleton();
19 | services.TryAddTransient();
20 | return services;
21 | }
22 |
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Ocelot.GrpcHttpGateway/Configuration/GrpcPipelineConfigurationExtensions.cs:
--------------------------------------------------------------------------------
1 | using Ocelot.Authentication.Middleware;
2 | using Ocelot.Authorisation.Middleware;
3 | using Ocelot.Cache.Middleware;
4 | using Ocelot.Claims.Middleware;
5 | using Ocelot.DownstreamUrlCreator.Middleware;
6 | using Ocelot.Headers.Middleware;
7 | using Ocelot.LoadBalancer.Middleware;
8 | using Ocelot.Middleware;
9 | using Ocelot.Middleware.Pipeline;
10 | using Ocelot.QueryStrings.Middleware;
11 | using Ocelot.RateLimit.Middleware;
12 | using Ocelot.Request.Middleware;
13 | using Ocelot.RequestId.Middleware;
14 | using System;
15 | using System.Threading.Tasks;
16 |
17 | namespace Ocelot.GrpcHttpGateway
18 | {
19 | public static class GrpcPipelineConfigurationExtensions
20 | {
21 |
22 | public static OcelotPipelineConfiguration AddGrpcHttpGateway(this OcelotPipelineConfiguration config)
23 | {
24 | config.MapWhenOcelotPipeline.Add(builder => builder.AddOrleansHttpGateway(config));
25 | return config;
26 | }
27 | ///
28 | ///
29 | ///
30 | private static Func AddOrleansHttpGateway(this IOcelotPipelineBuilder builder, OcelotPipelineConfiguration pipelineConfiguration)
31 | {
32 |
33 | // Now we have the ds route we can transform headers and stuff?
34 | builder.UseHttpHeadersTransformationMiddleware();
35 |
36 | // Initialises downstream request
37 | builder.UseDownstreamRequestInitialiser();
38 |
39 | // We check whether the request is ratelimit, and if there is no continue processing
40 | builder.UseRateLimiting();
41 |
42 | // This adds or updates the request id (initally we try and set this based on global config in the error handling middleware)
43 | // If anything was set at global level and we have a different setting at re route level the global stuff will be overwritten
44 | // This means you can get a scenario where you have a different request id from the first piece of middleware to the request id middleware.
45 | builder.UseRequestIdMiddleware();
46 |
47 | // Allow pre authentication logic. The idea being people might want to run something custom before what is built in.
48 | builder.UseIfNotNull(pipelineConfiguration.PreAuthenticationMiddleware);
49 |
50 | // Now we know where the client is going to go we can authenticate them.
51 | // We allow the ocelot middleware to be overriden by whatever the
52 | // user wants
53 | if (pipelineConfiguration.AuthenticationMiddleware == null)
54 | {
55 | builder.UseAuthenticationMiddleware();
56 | }
57 | else
58 | {
59 | builder.Use(pipelineConfiguration.AuthenticationMiddleware);
60 | }
61 |
62 | // The next thing we do is look at any claims transforms in case this is important for authorisation
63 | builder.UseClaimsBuilderMiddleware();
64 |
65 | // Allow pre authorisation logic. The idea being people might want to run something custom before what is built in.
66 | builder.UseIfNotNull(pipelineConfiguration.PreAuthorisationMiddleware);
67 |
68 | // Now we have authenticated and done any claims transformation we
69 | // can authorise the request
70 | // We allow the ocelot middleware to be overriden by whatever the
71 | // user wants
72 | if (pipelineConfiguration.AuthorisationMiddleware == null)
73 | {
74 | builder.UseAuthorisationMiddleware();
75 | }
76 | else
77 | {
78 | builder.Use(pipelineConfiguration.AuthorisationMiddleware);
79 | }
80 |
81 | // Now we can run any header transformation logic
82 | builder.UseHttpRequestHeadersBuilderMiddleware();
83 |
84 | // Allow the user to implement their own query string manipulation logic
85 | builder.UseIfNotNull(pipelineConfiguration.PreQueryStringBuilderMiddleware);
86 |
87 | // Now we can run any query string transformation logic
88 | builder.UseQueryStringBuilderMiddleware();
89 | // Get the load balancer for this request
90 | builder.UseLoadBalancingMiddleware();
91 |
92 | // This takes the downstream route we retrieved earlier and replaces any placeholders with the variables that should be used
93 | builder.UseDownstreamUrlCreatorMiddleware();
94 |
95 | // Not sure if this is the best place for this but we use the downstream url
96 | // as the basis for our cache key.
97 | builder.UseOutputCacheMiddleware();
98 |
99 |
100 | builder.UseGrpcHttpMiddleware();
101 |
102 | //builder.UseHttpRequesterMiddleware();
103 |
104 |
105 |
106 | return (context) =>
107 | {
108 | return context.DownstreamReRoute.DownstreamScheme.Equals("grpc", StringComparison.OrdinalIgnoreCase);
109 | };
110 | }
111 |
112 | private static void UseIfNotNull(this IOcelotPipelineBuilder builder,
113 | Func, Task> middleware)
114 | {
115 | if (middleware != null)
116 | {
117 | builder.Use(middleware);
118 | }
119 | }
120 | }
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/src/Ocelot.GrpcHttpGateway/GrpcHttpMiddleware.cs:
--------------------------------------------------------------------------------
1 | using Grpc.Core;
2 | using Microsoft.AspNetCore.Http;
3 | using Microsoft.Extensions.Options;
4 | using Newtonsoft.Json;
5 | using Ocelot.Errors;
6 | using Ocelot.Logging;
7 | using Ocelot.Middleware;
8 | using Ocelot.Responses;
9 | using System;
10 | using System.Net;
11 | using System.Net.Http;
12 | using System.Threading;
13 | using System.Threading.Tasks;
14 |
15 | namespace Ocelot.GrpcHttpGateway
16 | {
17 | public class GrpcHttpMiddleware : OcelotMiddleware
18 | {
19 | private readonly OcelotRequestDelegate next;
20 | private readonly IGrpcChannelFactory grpcChannelFactory;
21 | private readonly IGrpcServiceDescriptor grpcServiceDescriptor;
22 | private readonly IGrpcRequestBuilder grpcRequestBuilder;
23 |
24 | public GrpcHttpMiddleware(OcelotRequestDelegate next,
25 | IGrpcChannelFactory grpcChannelFactory,
26 | IGrpcServiceDescriptor grpcServiceDescriptor,
27 | IGrpcRequestBuilder grpcRequestBuilder,
28 | IOcelotLoggerFactory factory) : base(factory.CreateLogger())
29 | {
30 | this.next = next;
31 | this.grpcChannelFactory = grpcChannelFactory;
32 | this.grpcServiceDescriptor = grpcServiceDescriptor;
33 | this.grpcRequestBuilder = grpcRequestBuilder;
34 | }
35 |
36 | public async Task Invoke(DownstreamContext context)
37 | {
38 | string resultMessage = string.Empty;
39 | var httpStatusCode = HttpStatusCode.OK;
40 | var buildRequest = grpcRequestBuilder.BuildRequest(context);
41 | if (buildRequest.IsError)
42 | {
43 | resultMessage = "bad request";
44 | httpStatusCode = HttpStatusCode.BadRequest;
45 | Logger.LogDebug(resultMessage);
46 | //SetPipelineError(context, buildRequest.Errors);
47 | }
48 | else
49 | {
50 | try
51 | {
52 | //缓存连接应该使用服务发现或执行健康检查,不如会等太久
53 | var channel = grpcChannelFactory.GetGrpcChannel(context.DownstreamRequest.Host, context.DownstreamRequest.Port);
54 | var client = new GrpcClient(channel);
55 |
56 | resultMessage = await client.InvokeMethodAsync(buildRequest.Data.GrpcMethod, buildRequest.Data.RequestMessage);
57 | }
58 | catch (RpcException ex)
59 | {
60 | httpStatusCode = HttpStatusCode.InternalServerError;
61 | resultMessage = $"rpc exception.";
62 | Logger.LogError($"{ex.StatusCode}--{ex.Message}", ex);
63 | }
64 | catch (Exception ex)
65 | {
66 | httpStatusCode = HttpStatusCode.ServiceUnavailable;
67 | resultMessage = $"error in request grpc service.";
68 | //SetPipelineError(context, new UnknownError(error));
69 | Logger.LogError($"{resultMessage}--{context.DownstreamRequest.ToUri()}", ex);
70 | }
71 | }
72 | OkResponse httpResponse = new OkResponse(new GrpcHttpContent(resultMessage));
73 | context.HttpContext.Response.ContentType = "application/json";
74 | context.DownstreamResponse = new DownstreamResponse(httpResponse.Data, httpStatusCode, httpResponse.Data.Headers);
75 | }
76 |
77 |
78 |
79 | }
80 |
81 | }
--------------------------------------------------------------------------------
/src/Ocelot.GrpcHttpGateway/GrpcHttpMiddlewareExtensions.cs:
--------------------------------------------------------------------------------
1 | using Ocelot.Middleware.Pipeline;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace Ocelot.GrpcHttpGateway
7 | {
8 | public static class GrpcHttpMiddlewareExtensions
9 | {
10 | public static IOcelotPipelineBuilder UseGrpcHttpMiddleware(this IOcelotPipelineBuilder builder)
11 | {
12 | return builder.UseMiddleware();
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Ocelot.GrpcHttpGateway/GrpcRequest/GrpcClient/ArgsParser.cs:
--------------------------------------------------------------------------------
1 | using Google.Protobuf;
2 | using Grpc.Core;
3 | using System;
4 |
5 | namespace Ocelot.GrpcHttpGateway
6 | {
7 | public static class ArgsParser where T : class, IMessage
8 | {
9 | public static MessageParser Parser = new MessageParser(() => Activator.CreateInstance());
10 | public static Marshaller Marshaller = Marshallers.Create((arg) => MessageExtensions.ToByteArray(arg), Parser.ParseFrom);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/Ocelot.GrpcHttpGateway/GrpcRequest/GrpcClient/GrpcChannelFactory.cs:
--------------------------------------------------------------------------------
1 | using Grpc.Core;
2 | using System;
3 | using System.Collections.Concurrent;
4 | using System.Collections.Generic;
5 | using System.Text;
6 |
7 | namespace Ocelot.GrpcHttpGateway
8 | {
9 | public class GrpcChannelFactory : IGrpcChannelFactory
10 | {
11 | private readonly object _syncObj = new object();
12 | private ConcurrentDictionary grpcServices;
13 |
14 | public GrpcChannelFactory()
15 | {
16 | grpcServices = new ConcurrentDictionary();
17 | }
18 | public Channel GetGrpcChannel(string address, int port)
19 | {
20 | string key = $"{address}:{port}";
21 | if (grpcServices.TryGetValue(key, out Channel channel))
22 | return channel;
23 | channel = new Channel(key, ChannelCredentials.Insecure);
24 | return grpcServices.GetOrAdd(key, channel);
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Ocelot.GrpcHttpGateway/GrpcRequest/GrpcClient/GrpcClient.cs:
--------------------------------------------------------------------------------
1 | using Google.Protobuf;
2 | using Google.Protobuf.Reflection;
3 | using Grpc.Core;
4 | using System;
5 | using System.Linq;
6 | using System.Reflection;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 |
10 | namespace Ocelot.GrpcHttpGateway
11 | {
12 | public class GrpcClient : ClientBase
13 | {
14 | public GrpcClient(Channel channel) : base(channel) { }
15 | public GrpcClient(CallInvoker callInvoker) : base(callInvoker) { }
16 | public GrpcClient() : base() { }
17 | protected GrpcClient(ClientBaseConfiguration configuration) : base(configuration) { }
18 |
19 | public K Invoke(MethodDescriptor method, T request) where T : class, IMessage where K : class, IMessage
20 | {
21 | var _method = GrpcMethod.GetMethod(method);
22 | return CallInvoker.BlockingUnaryCall(_method, null, GetDefaultCallOptions(), request);
23 | }
24 | public AsyncUnaryCall InvokeAsync(MethodDescriptor method, T request) where T : class, IMessage where K : class, IMessage
25 | {
26 | var _method = GrpcMethod.GetMethod(method);
27 | return CallInvoker.AsyncUnaryCall(_method, null, GetDefaultCallOptions(), request);
28 | }
29 | public virtual string Invoke(MethodDescriptor method, string message) where T : class, IMessage where K : class, IMessage
30 | {
31 | var req = ArgsParser.Parser.ParseJson(message);
32 | var _method = GrpcMethod.GetMethod(method);
33 | return CallInvoker.BlockingUnaryCall(_method, null, GetDefaultCallOptions(), req).ToString();
34 | }
35 | public virtual async Task InvokeAsync(MethodDescriptor method, string message)
36 | where T : class, IMessage where K : class, IMessage
37 | {
38 | return await InvokeAsync(method, message, GetDefaultCallOptions());
39 | }
40 | public virtual async Task InvokeAsync(MethodDescriptor method, string message, CallOptions callOptions)
41 | where T : class, IMessage where K : class, IMessage
42 | {
43 | return await InvokeAsync(method, message, GetDefaultCallOptions(), null);
44 | }
45 | public virtual async Task InvokeAsync(MethodDescriptor methodDescript, string message, CallOptions callOptions, string host)
46 | where T : class, IMessage where K : class, IMessage
47 | {
48 | var request = ArgsParser.Parser.ParseJson(message);
49 | var method = GrpcMethod.GetMethod(methodDescript);
50 | K response = await CallInvoker.AsyncUnaryCall(method, host, callOptions, request);
51 | return response.ToString();
52 | }
53 |
54 | protected override GrpcClient NewInstance(ClientBaseConfiguration configuration)
55 | {
56 | return new GrpcClient(configuration);
57 | }
58 | ///需要添加CallOptions参数,为请求添加更多header
59 | public object InvokeMethod(MethodDescriptor method, string message)
60 | {
61 | object[] obj = { method, message };
62 | string name = "Invoke";
63 | Type[] parameterType = { typeof(MethodDescriptor), typeof(string) };
64 | return InvokeMethod(this, method, parameterType, name, obj);
65 | }
66 | public async Task InvokeMethodAsync(MethodDescriptor method, string message)
67 | {
68 | return await InvokeMethodAsync(method, message, GetDefaultCallOptions());
69 | }
70 | public async Task InvokeMethodAsync(MethodDescriptor method, string message, CallOptions callOptions)
71 | {
72 | return await InvokeMethodAsync(method, message, GetDefaultCallOptions(), null);
73 |
74 | //object[] obj = { method, message, callOptions };
75 | //string name = "InvokeAsync";
76 | //Type[] parameterType = { typeof(MethodDescriptor), typeof(string),typeof(CallOptions) };
77 | //Type[] templateTypeSet = { method.InputType.ClrType, method.OutputType.ClrType };
78 |
79 | //var task = InvokeMethodAsync(typeof(GrpcClient), this, templateTypeSet, parameterType, name, obj);
80 | //return await (task as Task);
81 | }
82 | public async Task InvokeMethodAsync(MethodDescriptor method, string message, CallOptions callOptions, string host)
83 | {
84 | object[] obj = { method, message, callOptions, host };
85 | string name = "InvokeAsync";
86 | Type[] parameterType = { typeof(MethodDescriptor), typeof(string), typeof(CallOptions), typeof(string) };
87 | Type[] templateTypeSet = { method.InputType.ClrType, method.OutputType.ClrType };
88 |
89 | var task = InvokeMethodAsync(typeof(GrpcClient), this, templateTypeSet, parameterType, name, obj);
90 | return await (task as Task);
91 | }
92 |
93 | static object InvokeMethod(GrpcClient grpcClient, MethodDescriptor method, Type[] parameterType, string name, params object[] args)
94 | {
95 | Type clsType = typeof(GrpcClient);
96 | Type[] templateTypeSet = { method.InputType.ClrType, method.OutputType.ClrType };
97 | MethodInfo methodInfo = clsType.GetMethod(name, parameterType);
98 | methodInfo = methodInfo.MakeGenericMethod(templateTypeSet);
99 | return methodInfo.Invoke(grpcClient, args);
100 | }
101 | [Obsolete("暂不使用")]
102 | static object InvokeMethod(Type clsType, object classInstance, Type[] templateTypeSet, Type[] parameterType, string name, params object[] args)
103 | {
104 | MethodInfo methodInfo = clsType.GetMethod(name, parameterType);
105 | methodInfo = methodInfo.MakeGenericMethod(templateTypeSet);
106 | return methodInfo.Invoke(classInstance, args);
107 | }
108 | ///
109 | /// 不转task了
110 | ///
111 | static object InvokeMethodAsync(Type clsType, object classInstance, Type[] templateTypeSet, Type[] parameterType, string name, params object[] args)
112 | {
113 | MethodInfo method = clsType.GetMethod(name, parameterType);
114 | method = method.MakeGenericMethod(templateTypeSet);
115 | return method.Invoke(classInstance, args);
116 | }
117 | private CallOptions GetDefaultCallOptions(int second = 30)
118 | {
119 | return new CallOptions(null, DateTime.UtcNow.AddSeconds(second), default(CancellationToken));
120 | }
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/src/Ocelot.GrpcHttpGateway/GrpcRequest/GrpcClient/GrpcMethod.cs:
--------------------------------------------------------------------------------
1 | using Google.Protobuf;
2 | using Google.Protobuf.Reflection;
3 | using Grpc.Core;
4 | using System;
5 | using System.Collections.Concurrent;
6 | using System.Collections.Generic;
7 |
8 | namespace Ocelot.GrpcHttpGateway
9 | {
10 | ///
11 | /// TODO:用SingletonDictionary进行改造
12 | ///
13 | ///
14 | ///
15 | public class GrpcMethod where TRequest : class, IMessage where KResult : class, IMessage
16 | {
17 | private static ConcurrentDictionary> methods
18 | = new ConcurrentDictionary>();
19 |
20 | public static Method GetMethod(MethodDescriptor methodDescriptor)
21 | {
22 | Method method;
23 | if (methods.TryGetValue(methodDescriptor, out method))
24 | return method;
25 |
26 | int mtype = 0;
27 | if (methodDescriptor.IsClientStreaming)
28 | mtype = 1;
29 | if (methodDescriptor.IsServerStreaming)
30 | mtype += 2;
31 | var methodType = (MethodType)Enum.ToObject(typeof(MethodType), mtype);
32 |
33 | var _method = new Method(methodType, methodDescriptor.Service.FullName
34 | , methodDescriptor.Name, ArgsParser.Marshaller, ArgsParser.Marshaller);
35 |
36 | methods.TryAdd(methodDescriptor, _method);
37 |
38 | return _method;
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Ocelot.GrpcHttpGateway/GrpcRequest/GrpcClient/IGrpcChannelFactory.cs:
--------------------------------------------------------------------------------
1 | using Grpc.Core;
2 |
3 | namespace Ocelot.GrpcHttpGateway
4 | {
5 | public interface IGrpcChannelFactory
6 | {
7 | Channel GetGrpcChannel(string address, int port);
8 | }
9 | }
--------------------------------------------------------------------------------
/src/Ocelot.GrpcHttpGateway/GrpcRequest/GrpcHttpContent.cs:
--------------------------------------------------------------------------------
1 | using Google.Protobuf;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Net;
6 | using System.Net.Http;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace Ocelot.GrpcHttpGateway
11 | {
12 | public class GrpcHttpContent: HttpContent
13 | {
14 | private string result;
15 |
16 | public GrpcHttpContent(string result)
17 | {
18 | this.result = result;
19 | }
20 |
21 | protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context)
22 | {
23 | var writer = new StreamWriter(stream);
24 | await writer.WriteAsync(result);
25 | await writer.FlushAsync();
26 | }
27 |
28 | protected override bool TryComputeLength(out long length)
29 | {
30 | length = result.Length;
31 | return true;
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Ocelot.GrpcHttpGateway/GrpcRequest/GrpcRequest.cs:
--------------------------------------------------------------------------------
1 | using Google.Protobuf;
2 | using Google.Protobuf.Reflection;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 |
7 | namespace Ocelot.GrpcHttpGateway
8 | {
9 | public class GrpcRequest
10 | {
11 | public MethodDescriptor GrpcMethod { get; set; }
12 |
13 | public string RequestMessage { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Ocelot.GrpcHttpGateway/GrpcRequest/GrpcRequestBuilder.cs:
--------------------------------------------------------------------------------
1 | using Google.Protobuf;
2 | using Microsoft.AspNetCore.Http;
3 | using Ocelot.Logging;
4 | using Ocelot.Middleware;
5 | using Ocelot.Request.Mapper;
6 | using Ocelot.Responses;
7 | using System;
8 | using System.Collections.Generic;
9 | using System.IO;
10 | using System.Text;
11 |
12 | namespace Ocelot.GrpcHttpGateway
13 | {
14 | public class GrpcRequestBuilder : IGrpcRequestBuilder
15 | {
16 | private readonly IOcelotLogger logger;
17 | private IGrpcServiceDescriptor grpcServiceDescriptor;
18 |
19 | public GrpcRequestBuilder(IOcelotLoggerFactory factory, IGrpcServiceDescriptor grpcServiceDescriptor)
20 | {
21 | this.logger = factory.CreateLogger();
22 | this.grpcServiceDescriptor = grpcServiceDescriptor;
23 | }
24 |
25 | public Response BuildRequest(DownstreamContext context)
26 | {
27 | var route = context.DownstreamRequest.AbsolutePath.Trim('/').Split('/');
28 | if (route.Length !=2)
29 | {
30 | return SetError($"error request:{route},must do like this:http://domain:port/grpc/ServiceName/MethordName/");
31 | }
32 | string svcName = route[0].ToUpper();
33 | string methodName = route[1].ToUpper();
34 | //判断是否存在对应grpc服务、方法
35 | var grpcDescript = grpcServiceDescriptor.GetGrpcDescript();
36 | if (!grpcDescript.ContainsKey(svcName))
37 | {
38 | return SetError($"service name is not defined.{svcName}");
39 | }
40 | if (!grpcDescript[svcName].ContainsKey(methodName))
41 | {
42 | return SetError($"method name is not defined.{methodName}");
43 | }
44 | GrpcRequest grpcRequest = new GrpcRequest
45 | {
46 | GrpcMethod = grpcDescript[svcName][methodName]
47 | };
48 | try
49 | {
50 | //需要替换Scheme
51 | context.DownstreamRequest.Scheme = "http";
52 | var requestMessage = context.DownstreamRequest.ToHttpRequestMessage();
53 | var stream = requestMessage.Content.ReadAsStreamAsync().Result;
54 | var encoding = context.HttpContext.Request.GetTypedHeaders().ContentType?.Encoding ?? Encoding.UTF8;
55 | using (var reader = new StreamReader(stream,encoding))
56 | {
57 | grpcRequest.RequestMessage = reader.ReadToEnd();
58 | }
59 | //兼容请求参数为空
60 | if (string.IsNullOrEmpty(grpcRequest.RequestMessage))
61 | {
62 | grpcRequest.RequestMessage = "{}";
63 | }
64 |
65 | }
66 | catch(Exception)
67 | {
68 | return SetError("request parameter error");
69 | }
70 | context.DownstreamRequest.Scheme = "grpc";
71 | return new OkResponse(grpcRequest);
72 | }
73 |
74 | ErrorResponse SetError(Exception exception)
75 | {
76 | return new ErrorResponse(new UnmappableRequestError(exception));
77 | }
78 | ErrorResponse SetError(string message)
79 | {
80 | var exception = new Exception(message);
81 | return SetError(exception);
82 | }
83 |
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/Ocelot.GrpcHttpGateway/GrpcRequest/IGrpcRequestBuilder.cs:
--------------------------------------------------------------------------------
1 | using Ocelot.Middleware;
2 | using Ocelot.Responses;
3 |
4 | namespace Ocelot.GrpcHttpGateway
5 | {
6 | public interface IGrpcRequestBuilder
7 | {
8 | Response BuildRequest(DownstreamContext context);
9 | }
10 | }
--------------------------------------------------------------------------------
/src/Ocelot.GrpcHttpGateway/GrpcRequest/UnknownError.cs:
--------------------------------------------------------------------------------
1 | using Ocelot.Errors;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace Ocelot.GrpcHttpGateway
7 | {
8 | public class UnknownError : Error
9 | {
10 | public UnknownError(string message) : base(message, OcelotErrorCode.UnknownError)
11 | {
12 | }
13 |
14 | public UnknownError(string message,Exception exception) : base(message, OcelotErrorCode.UnknownError)
15 | {
16 | }
17 |
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Ocelot.GrpcHttpGateway/Ocelot.GrpcHttpGateway.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/Ocelot.GrpcHttpGateway/Ocelot.GrpcHttpGateway.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | false
5 |
6 |
--------------------------------------------------------------------------------
/src/Ocelot.GrpcHttpGateway/ServiceDescriptor/GrpcServiceDescriptor.cs:
--------------------------------------------------------------------------------
1 | using Google.Protobuf;
2 | using Google.Protobuf.Reflection;
3 | using System;
4 | using System.Collections.Concurrent;
5 | using System.Collections.Generic;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Reflection;
9 | using System.Text;
10 | using System.Text.RegularExpressions;
11 |
12 | namespace Ocelot.GrpcHttpGateway
13 | {
14 | public class GrpcServiceDescriptor : IGrpcServiceDescriptor
15 | {
16 | protected ConcurrentDictionary> CurrentService = new ConcurrentDictionary>();
17 | protected string pattern = "^System|^mscorlib|^Microsoft|^Autofac|^EntityFramework|^Fluent|^Newtonsoft|^netstandard|^Npgsql|^NLog|^MySql|^Anonymously|^DynamicProxyGenAssembly";
18 |
19 | public GrpcServiceDescriptor()
20 | {
21 | LoadGrpcAssmbly();
22 | }
23 |
24 | public virtual ConcurrentDictionary> GetGrpcDescript()
25 | {
26 | return CurrentService;
27 | }
28 |
29 | protected virtual void LoadGrpcAssmbly(string path = "")
30 | {
31 | if (string.IsNullOrEmpty(path))
32 | path = AppContext.BaseDirectory;
33 | var assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();
34 | foreach (var file in Directory.GetFiles(path, "*.dll"))
35 | {
36 | assemblies.Add(Assembly.LoadFile(file));
37 | }
38 | foreach (var assembly in assemblies)
39 | {
40 | if (Regex.IsMatch(assembly.FullName, pattern, RegexOptions.IgnoreCase | RegexOptions.Compiled))
41 | continue;
42 | GetGrpcDescript(assembly.GetTypes());
43 | }
44 |
45 | }
46 |
47 | protected virtual void GetGrpcDescript(Type[] types)
48 | {
49 | //根据类名特点查找FileDescriptor
50 | var fileTypes = types.Where(type => type.Name.Contains("Reflection"));
51 | foreach (var type in fileTypes)
52 | {
53 | BindingFlags flag = BindingFlags.Static | BindingFlags.Public;
54 | var property = type.GetProperties(flag).FirstOrDefault();
55 | if (property is null)
56 | continue;
57 | var fileDescriptor = property.GetValue(null) as FileDescriptor;
58 | if (fileDescriptor is null)
59 | continue;
60 |
61 | foreach (var svr in fileDescriptor.Services)
62 | {
63 | if (CurrentService.ContainsKey(svr.Name.ToUpper()))
64 | continue;
65 | if (CurrentService.TryAdd(svr.Name.ToUpper(), new ConcurrentDictionary()))
66 | foreach (var method in svr.Methods)
67 | {
68 | CurrentService[svr.Name.ToUpper()].TryAdd(method.Name.ToUpper(), method);
69 | }
70 | }
71 | }
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/Ocelot.GrpcHttpGateway/ServiceDescriptor/IGrpcServiceDescriptor.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Concurrent;
2 | using System.Collections.Generic;
3 | using Google.Protobuf.Reflection;
4 |
5 | namespace Ocelot.GrpcHttpGateway
6 | {
7 | public interface IGrpcServiceDescriptor
8 | {
9 | ConcurrentDictionary> GetGrpcDescript();
10 | }
11 | }
--------------------------------------------------------------------------------
/src/WebGateway/DefaultServiceDescriptor.cs:
--------------------------------------------------------------------------------
1 | using Google.Protobuf.Reflection;
2 | using Ocelot.GrpcHttpGateway;
3 | using System;
4 | using System.Collections.Concurrent;
5 | using System.Collections.Generic;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Reflection;
9 | using System.Text.RegularExpressions;
10 | using System.Threading.Tasks;
11 |
12 | namespace WebGateway
13 | {
14 | public class DefaultServiceDescriptor : GrpcServiceDescriptor, IGrpcServiceDescriptor
15 | {
16 |
17 | public override ConcurrentDictionary> GetGrpcDescript()
18 | {
19 | return CurrentService;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/WebGateway/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.Extensions.Configuration;
9 | using Microsoft.Extensions.Logging;
10 |
11 | namespace WebGateway
12 | {
13 | public class Program
14 | {
15 | static readonly string IP = "127.0.0.1";
16 | static readonly string Port = "5000";
17 | public static void Main(string[] args)
18 | {
19 | CreateWebHostBuilder(args).Build().Run();
20 | }
21 |
22 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
23 | WebHost.CreateDefaultBuilder(args)
24 | .UseStartup()
25 | .UseKestrel()
26 | .UseUrls($"http://{IP}:{Port}")
27 | .ConfigureAppConfiguration((hostingContext, builder) =>
28 | {
29 | builder.AddJsonFile("ocelot.json", false, true);
30 | });
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/WebGateway/Properties/PublishProfiles/FolderProfile.pubxml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 | FileSystem
9 | FileSystem
10 | Release
11 | Any CPU
12 |
13 | True
14 | False
15 | 6c443297-1e33-4001-8df0-b6d014fa157f
16 | bin\Debug\netcoreapp2.1\publish\
17 | False
18 | netcoreapp2.1
19 | false
20 | <_IsPortable>true
21 |
22 |
--------------------------------------------------------------------------------
/src/WebGateway/Properties/PublishProfiles/FolderProfile.pubxml.user:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 | <_PublishTargetUrl>D:\source\Projects\GrpcProject\src\WaterIot\Test\WebGateway\bin\Debug\netcoreapp2.1\publish\
10 |
11 |
--------------------------------------------------------------------------------
/src/WebGateway/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:5000",
7 | "sslPort": 0
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "environmentVariables": {
15 | "ASPNETCORE_ENVIRONMENT": "Development"
16 | }
17 | },
18 | "WebGateway": {
19 | "commandName": "Project",
20 | "launchBrowser": true,
21 | "applicationUrl": "http://localhost:5000",
22 | "environmentVariables": {
23 | "ASPNETCORE_ENVIRONMENT": "Development"
24 | }
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/src/WebGateway/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Builder;
6 | using Microsoft.AspNetCore.Hosting;
7 | using Microsoft.AspNetCore.Http;
8 | using Microsoft.Extensions.Configuration;
9 | using Microsoft.Extensions.DependencyInjection;
10 | using Ocelot.DependencyInjection;
11 | using Ocelot.Middleware;
12 | using Ocelot.GrpcHttpGateway;
13 | using Microsoft.Extensions.DependencyInjection.Extensions;
14 |
15 | namespace WebGateway
16 | {
17 | public class Startup
18 | {
19 | public Startup(IConfiguration configuration)
20 | {
21 | Configuration = configuration;
22 | }
23 |
24 | public IConfiguration Configuration { get; }
25 | // This method gets called by the runtime. Use this method to add services to the container.
26 | // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
27 | public void ConfigureServices(IServiceCollection services)
28 | {
29 |
30 | services.AddOcelot(Configuration).AddGrpcHttpGateway();
31 | services.AddSingleton();
32 | }
33 |
34 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
35 | public void Configure(IApplicationBuilder app, IHostingEnvironment env)
36 | {
37 | if (env.IsDevelopment())
38 | {
39 | app.UseDeveloperExceptionPage();
40 | }
41 |
42 | app.UseOcelot(config =>
43 | {
44 | config.AddGrpcHttpGateway();
45 | }).Wait();
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/WebGateway/WebGateway.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | PreserveNewest
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/WebGateway/WebGateway.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ProjectDebugger
5 |
6 |
7 | WebGateway
8 | FolderProfile
9 |
10 |
--------------------------------------------------------------------------------
/src/WebGateway/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "ConnectionStrings": {
3 | "DefaultConnection": "Server=(localdb)\\MSSQLLocalDB;Database=_CHANGE_ME;Trusted_Connection=True;MultipleActiveResultSets=true"
4 | },
5 | "Logging": {
6 | "LogLevel": {
7 | "Default": "Warning"
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/src/WebGateway/ocelot.json:
--------------------------------------------------------------------------------
1 | {
2 | "ReRoutes": [
3 | {
4 | "DownstreamPathTemplate": "/{url}",
5 | "DownstreamScheme": "http",
6 | "DownstreamHostAndPorts": [
7 | {
8 | "Host": "127.0.0.1",
9 | "Port": "5001"
10 | }
11 | ],
12 | "UpstreamPathTemplate": "/lb1/{url}",
13 | "UpstreamHttpMethod": [ "Get", "Post" ]
14 | },
15 | {
16 | "DownstreamPathTemplate": "/{url}",
17 | "DownstreamScheme": "http",
18 | "DownstreamHostAndPorts": [
19 | {
20 | "Host": "127.0.0.1",
21 | "Port": "5002"
22 | }
23 | ],
24 | "UpstreamPathTemplate": "/lb2/{url}",
25 | "UpstreamHttpMethod": [ "Get", "Post" ]
26 | },
27 | {
28 | "DownstreamPathTemplate": "/{url}",
29 | "DownstreamScheme": "http",
30 | "DownstreamHostAndPorts": [
31 | {
32 | "Host": "127.0.0.1",
33 | "Port": 5001
34 | },
35 | {
36 | "Host": "127.0.0.1",
37 | "Port": 5002
38 | }
39 |
40 | ],
41 | "UpstreamPathTemplate": "/lb/{url}",
42 | "LoadBalancerOptions": {
43 | "Type": "RoundRobin"
44 | },
45 | "UpstreamHttpMethod": [ "Get", "Post" ]
46 | },
47 |
48 | {
49 | "DownstreamPathTemplate": "/{url}",
50 | "DownstreamScheme": "grpc",
51 | "DownstreamHostAndPorts": [
52 | {
53 | "Host": "127.0.0.1",
54 | "Port": 50001
55 | },
56 | {
57 | "Host": "127.0.0.1",
58 | "Port": 50002
59 | }
60 |
61 | ],
62 | "UpstreamPathTemplate": "/grpc/{url}",
63 | "LoadBalancerOptions": {
64 | "Type": "RoundRobin" //LeastConnection,RoundRobin,NoLoadBalance(无或者服务发现)
65 | },
66 | "UpstreamHttpMethod": [ "Get", "Post" ]
67 | }
68 | ]
69 | }
--------------------------------------------------------------------------------