48 std::string comments = location.leading_comments.empty()
49 ? location.trailing_comments
50 : location.leading_comments;
51 if (comments.empty()) {
60 std::vector<std::string>
lines;
66 printer->Print(
"/// <summary>\n");
67 bool last_was_empty =
false;
79 last_was_empty =
true;
82 printer->Print(
"///\n");
84 last_was_empty =
false;
85 printer->Print(
"///$line$\n",
"line", *
it);
88 printer->Print(
"/// </summary>\n");
99 "[global::System.CodeDom.Compiler.GeneratedCode(\"grpc_csharp_plugin\", "
103 template <
typename DescriptorType>
107 if (!
descriptor->GetSourceLocation(&location)) {
110 return GenerateDocCommentBodyImpl(printer, location);
116 if (
method->client_streaming()) {
118 "/// <param name=\"requestStream\">Used for reading requests from "
119 "the client.</param>\n");
122 "/// <param name=\"request\">The request received from the "
123 "client.</param>\n");
125 if (
method->server_streaming()) {
127 "/// <param name=\"responseStream\">Used for sending responses back "
128 "to the client.</param>\n");
131 "/// <param name=\"context\">The context of the server-side call "
132 "handler being invoked.</param>\n");
133 if (
method->server_streaming()) {
135 "/// <returns>A task indicating completion of the "
136 "handler.</returns>\n");
139 "/// <returns>The response to send back to the client (wrapped by a "
140 "task).</returns>\n");
147 bool is_sync,
bool use_call_options) {
149 if (!
method->client_streaming()) {
151 "/// <param name=\"request\">The request to send to the "
152 "server.</param>\n");
154 if (!use_call_options) {
156 "/// <param name=\"headers\">The initial metadata to send with the "
157 "call. This parameter is optional.</param>\n");
159 "/// <param name=\"deadline\">An optional deadline for the call. The "
160 "call will be cancelled if deadline is hit.</param>\n");
162 "/// <param name=\"cancellationToken\">An optional token for "
163 "canceling the call.</param>\n");
166 "/// <param name=\"options\">The options for the call.</param>\n");
170 "/// <returns>The response received from the server.</returns>\n");
172 printer->Print(
"/// <returns>The call object.</returns>\n");
182 return service->name() +
"Client";
186 return service->name() +
"Base";
190 if (
method->client_streaming()) {
191 if (
method->server_streaming()) {
192 return "grpc::MethodType.DuplexStreaming";
194 return "grpc::MethodType.ClientStreaming";
197 if (
method->server_streaming()) {
198 return "grpc::MethodType.ServerStreaming";
200 return "grpc::MethodType.Unary";
206 if (
method->client_streaming()) {
207 if (
method->server_streaming()) {
208 return "grpc::DuplexStreamingServerMethod";
210 return "grpc::ClientStreamingServerMethod";
213 if (
method->server_streaming()) {
214 return "grpc::ServerStreamingServerMethod";
216 return "grpc::UnaryServerMethod";
221 std::string GetServiceNameFieldName() {
return "__ServiceName"; }
224 return "__Marshaller_" +
229 return "__Method_" +
method->name();
233 bool invocation_param =
false) {
234 if (
method->client_streaming()) {
237 if (invocation_param) {
244 return internal_access ?
"internal" :
"public";
248 if (
method->client_streaming()) {
249 if (
method->server_streaming()) {
250 return "grpc::AsyncDuplexStreamingCall<" +
254 return "grpc::AsyncClientStreamingCall<" +
259 if (
method->server_streaming()) {
260 return "grpc::AsyncServerStreamingCall<" +
263 return "grpc::AsyncUnaryCall<" +
270 if (
method->client_streaming()) {
271 return "grpc::IAsyncStreamReader<" +
279 if (
method->server_streaming()) {
280 return "global::System.Threading.Tasks.Task";
282 return "global::System.Threading.Tasks.Task<" +
287 if (
method->server_streaming()) {
288 return ", grpc::IServerStreamWriter<" +
296 std::vector<const Descriptor*> GetUsedMessages(
298 std::set<const Descriptor*> descriptor_set;
299 std::vector<const Descriptor*>
301 for (
int i = 0;
i <
service->method_count();
i++) {
303 if (descriptor_set.find(
method->input_type()) == descriptor_set.end()) {
304 descriptor_set.insert(
method->input_type());
307 if (descriptor_set.find(
method->output_type()) == descriptor_set.end()) {
308 descriptor_set.insert(
method->output_type());
316 std::vector<const Descriptor*> used_messages = GetUsedMessages(
service);
317 if (used_messages.size() != 0) {
319 GenerateGeneratedCodeAttribute(
out);
321 "static void __Helper_SerializeMessage("
322 "global::Google.Protobuf.IMessage message, "
323 "grpc::SerializationContext context)\n"
327 "#if !GRPC_DISABLE_PROTOBUF_BUFFER_SERIALIZATION\n"
328 "if (message is global::Google.Protobuf.IBufferMessage)\n"
332 "context.SetPayloadLength(message.CalculateSize());\n"
333 "global::Google.Protobuf.MessageExtensions.WriteTo(message, "
334 "context.GetBufferWriter());\n"
335 "context.Complete();\n"
343 "global::Google.Protobuf.MessageExtensions.ToByteArray(message));\n");
347 GenerateGeneratedCodeAttribute(
out);
349 "static class __Helper_MessageCache<T>\n"
353 "public static readonly bool IsBufferMessage = "
354 "global::System.Reflection.IntrospectionExtensions.GetTypeInfo(typeof("
355 "global::Google.Protobuf.IBufferMessage)).IsAssignableFrom(typeof(T));"
360 GenerateGeneratedCodeAttribute(
out);
362 "static T __Helper_DeserializeMessage<T>("
363 "grpc::DeserializationContext context, "
364 "global::Google.Protobuf.MessageParser<T> parser) "
365 "where T : global::Google.Protobuf.IMessage<T>\n"
369 "#if !GRPC_DISABLE_PROTOBUF_BUFFER_SERIALIZATION\n"
370 "if (__Helper_MessageCache<T>.IsBufferMessage)\n"
374 "return parser.ParseFrom(context.PayloadAsReadOnlySequence());\n");
379 out->Print(
"return parser.ParseFrom(context.PayloadAsNewBuffer());\n");
384 for (
size_t i = 0;
i < used_messages.size();
i++) {
386 GenerateGeneratedCodeAttribute(
out);
388 "static readonly grpc::Marshaller<$type$> $fieldname$ = "
389 "grpc::Marshallers.Create(__Helper_SerializeMessage, "
390 "context => __Helper_DeserializeMessage(context, $type$.Parser));\n",
391 "fieldname", GetMarshallerFieldName(
message),
"type",
398 GenerateGeneratedCodeAttribute(
out);
400 "static readonly grpc::Method<$request$, $response$> $fieldname$ = new "
401 "grpc::Method<$request$, $response$>(\n",
402 "fieldname", GetMethodFieldName(
method),
"request",
407 out->Print(
"$methodtype$,\n",
"methodtype", GetCSharpMethodType(
method));
408 out->Print(
"$servicenamefield$,\n",
"servicenamefield",
409 GetServiceNameFieldName());
410 out->Print(
"\"$methodname$\",\n",
"methodname",
method->name());
411 out->Print(
"$requestmarshaller$,\n",
"requestmarshaller",
412 GetMarshallerFieldName(
method->input_type()));
413 out->Print(
"$responsemarshaller$);\n",
"responsemarshaller",
414 GetMarshallerFieldName(
method->output_type()));
420 void GenerateServiceDescriptorProperty(
Printer*
out,
422 std::ostringstream
index;
424 out->Print(
"/// <summary>Service descriptor</summary>\n");
426 "public static global::Google.Protobuf.Reflection.ServiceDescriptor "
429 out->Print(
" get { return $umbrella$.Descriptor.Services[$index$]; }\n",
432 "index",
index.str());
439 "/// <summary>Base class for server-side implementations of "
440 "$servicename$</summary>\n",
441 "servicename", GetServiceClassName(
service));
443 "[grpc::BindServiceMethod(typeof($classname$), "
444 "\"BindService\")]\n",
445 "classname", GetServiceClassName(
service));
446 out->Print(
"public abstract partial class $name$\n",
"name",
450 for (
int i = 0;
i <
service->method_count();
i++) {
452 GenerateDocCommentServerMethod(
out,
method);
453 GenerateGeneratedCodeAttribute(
out);
455 "public virtual $returntype$ "
456 "$methodname$($request$$response_stream_maybe$, "
457 "grpc::ServerCallContext context)\n",
458 "methodname",
method->name(),
"returntype",
459 GetMethodReturnTypeServer(
method),
"request",
460 GetMethodRequestParamServer(
method),
"response_stream_maybe",
461 GetMethodResponseStreamMaybe(
method));
465 "throw new grpc::RpcException("
466 "new grpc::Status(grpc::StatusCode.Unimplemented, \"\"));\n");
476 out->Print(
"/// <summary>Client for $servicename$</summary>\n",
"servicename",
478 out->Print(
"public partial class $name$ : grpc::ClientBase<$name$>\n",
"name",
485 "/// <summary>Creates a new client for $servicename$</summary>\n"
486 "/// <param name=\"channel\">The channel to use to make remote "
488 "servicename", GetServiceClassName(
service));
489 GenerateGeneratedCodeAttribute(
out);
490 out->Print(
"public $name$(grpc::ChannelBase channel) : base(channel)\n",
491 "name", GetClientClassName(
service));
495 "/// <summary>Creates a new client for $servicename$ that uses a custom "
496 "<c>CallInvoker</c>.</summary>\n"
497 "/// <param name=\"callInvoker\">The callInvoker to use to make remote "
499 "servicename", GetServiceClassName(
service));
500 GenerateGeneratedCodeAttribute(
out);
502 "public $name$(grpc::CallInvoker callInvoker) : base(callInvoker)\n",
503 "name", GetClientClassName(
service));
507 "/// <summary>Protected parameterless constructor to allow creation"
508 " of test doubles.</summary>\n");
509 GenerateGeneratedCodeAttribute(
out);
510 out->Print(
"protected $name$() : base()\n",
"name",
515 "/// <summary>Protected constructor to allow creation of configured "
516 "clients.</summary>\n"
517 "/// <param name=\"configuration\">The client configuration.</param>\n");
518 GenerateGeneratedCodeAttribute(
out);
520 "protected $name$(ClientBaseConfiguration configuration)"
521 " : base(configuration)\n",
522 "name", GetClientClassName(
service));
526 for (
int i = 0;
i <
service->method_count();
i++) {
528 if (!
method->client_streaming() && !
method->server_streaming()) {
530 GenerateDocCommentClientMethod(
out,
method,
true,
false);
531 GenerateGeneratedCodeAttribute(
out);
533 "public virtual $response$ $methodname$($request$ request, "
535 "headers = null, global::System.DateTime? deadline = null, "
536 "global::System.Threading.CancellationToken "
537 "cancellationToken = "
538 "default(global::System.Threading.CancellationToken))\n",
539 "methodname",
method->name(),
"request",
545 "return $methodname$(request, new grpc::CallOptions(headers, "
547 "cancellationToken));\n",
548 "methodname",
method->name());
553 GenerateDocCommentClientMethod(
out,
method,
true,
true);
554 GenerateGeneratedCodeAttribute(
out);
556 "public virtual $response$ $methodname$($request$ request, "
557 "grpc::CallOptions options)\n",
558 "methodname",
method->name(),
"request",
564 "return CallInvoker.BlockingUnaryCall($methodfield$, null, options, "
566 "methodfield", GetMethodFieldName(
method));
572 if (!
method->client_streaming() && !
method->server_streaming()) {
575 GenerateDocCommentClientMethod(
out,
method,
false,
false);
576 GenerateGeneratedCodeAttribute(
out);
578 "public virtual $returntype$ "
579 "$methodname$($request_maybe$grpc::Metadata "
580 "headers = null, global::System.DateTime? deadline = null, "
581 "global::System.Threading.CancellationToken "
582 "cancellationToken = "
583 "default(global::System.Threading.CancellationToken))\n",
585 GetMethodRequestParamMaybe(
method),
"returntype",
586 GetMethodReturnTypeClient(
method));
591 "return $methodname$($request_maybe$new grpc::CallOptions(headers, "
593 "cancellationToken));\n",
595 GetMethodRequestParamMaybe(
method,
true));
600 GenerateDocCommentClientMethod(
out,
method,
false,
true);
601 GenerateGeneratedCodeAttribute(
out);
603 "public virtual $returntype$ "
604 "$methodname$($request_maybe$grpc::CallOptions "
607 GetMethodRequestParamMaybe(
method),
"returntype",
608 GetMethodReturnTypeClient(
method));
611 if (!
method->client_streaming() && !
method->server_streaming()) {
614 "return CallInvoker.AsyncUnaryCall($methodfield$, null, options, "
616 "methodfield", GetMethodFieldName(
method));
617 }
else if (
method->client_streaming() && !
method->server_streaming()) {
620 "return CallInvoker.AsyncClientStreamingCall($methodfield$, null, "
622 "methodfield", GetMethodFieldName(
method));
623 }
else if (!
method->client_streaming() &&
method->server_streaming()) {
626 "return CallInvoker.AsyncServerStreamingCall($methodfield$, null, "
627 "options, request);\n",
628 "methodfield", GetMethodFieldName(
method));
632 "return CallInvoker.AsyncDuplexStreamingCall($methodfield$, null, "
634 "methodfield", GetMethodFieldName(
method));
642 "/// <summary>Creates a new instance of client from given "
643 "<c>ClientBaseConfiguration</c>.</summary>\n");
644 GenerateGeneratedCodeAttribute(
out);
646 "protected override $name$ NewInstance(ClientBaseConfiguration "
648 "name", GetClientClassName(
service));
651 out->Print(
"return new $name$(configuration);\n",
"name",
663 "/// <summary>Creates service definition that can be registered with a "
664 "server</summary>\n");
666 "/// <param name=\"serviceImpl\">An object implementing the server-side"
667 " handling logic.</param>\n");
668 GenerateGeneratedCodeAttribute(
out);
670 "public static grpc::ServerServiceDefinition BindService($implclass$ "
672 "implclass", GetServerClassName(
service));
676 out->Print(
"return grpc::ServerServiceDefinition.CreateBuilder()");
679 for (
int i = 0;
i <
service->method_count();
i++) {
681 out->Print(
"\n.AddMethod($methodfield$, serviceImpl.$methodname$)",
682 "methodfield", GetMethodFieldName(
method),
"methodname",
685 out->Print(
".Build();\n");
694 void GenerateBindServiceWithBinderMethod(
Printer*
out,
697 "/// <summary>Register service method with a service "
698 "binder with or without implementation. Useful when customizing the "
699 "service binding logic.\n"
700 "/// Note: this method is part of an experimental API that can change or "
702 "removed without any prior notice.</summary>\n");
704 "/// <param name=\"serviceBinder\">Service methods will be bound by "
705 "calling <c>AddMethod</c> on this object."
708 "/// <param name=\"serviceImpl\">An object implementing the server-side"
709 " handling logic.</param>\n");
710 GenerateGeneratedCodeAttribute(
out);
712 "public static void BindService(grpc::ServiceBinderBase serviceBinder, "
715 "implclass", GetServerClassName(
service));
719 for (
int i = 0;
i <
service->method_count();
i++) {
722 "serviceBinder.AddMethod($methodfield$, serviceImpl == null ? null : "
723 "new $servermethodtype$<$inputtype$, $outputtype$>("
724 "serviceImpl.$methodname$));\n",
725 "methodfield", GetMethodFieldName(
method),
"servermethodtype",
726 GetCSharpServerMethodType(
method),
"inputtype",
738 bool generate_client,
bool generate_server,
739 bool internal_access) {
742 out->Print(
"$access_level$ static partial class $classname$\n",
743 "access_level", GetAccessLevel(internal_access),
"classname",
747 out->Print(
"static readonly string $servicenamefield$ = \"$servicename$\";\n",
748 "servicenamefield", GetServiceNameFieldName(),
"servicename",
753 for (
int i = 0;
i <
service->method_count();
i++) {
754 GenerateStaticMethodField(
out,
service->method(
i));
756 GenerateServiceDescriptorProperty(
out,
service);
758 if (generate_server) {
761 if (generate_client) {
764 if (generate_server) {
766 GenerateBindServiceWithBinderMethod(
out,
service);
776 bool generate_server,
bool internal_access) {
786 if (
file->service_count() == 0) {
791 out.Print(
"// <auto-generated>\n");
793 "// Generated by the protocol buffer compiler. DO NOT EDIT!\n");
794 out.Print(
"// source: $filename$\n",
"filename",
file->
name());
795 out.Print(
"// </auto-generated>\n");
799 if (!leading_comments.empty()) {
800 out.Print(
"// Original file comments:\n");
801 out.PrintRaw(leading_comments.c_str());
804 out.Print(
"#pragma warning disable 0414, 1591, 8981\n");
806 out.Print(
"#region Designer generated code\n");
808 out.Print(
"using grpc = global::Grpc.Core;\n");
812 if (file_namespace !=
"") {
813 out.Print(
"namespace $namespace$ {\n",
"namespace", file_namespace);
816 for (
int i = 0;
i <
file->service_count();
i++) {
817 GenerateService(&
out,
file->service(
i), generate_client, generate_server,
820 if (file_namespace !=
"") {
824 out.Print(
"#endregion\n");