private void WriteNoRequestParameterMethod(
        CodeWriter writer,
        string key,
        RpcCallSchemaModel call,
        Dictionary <string, string> methodMap)
    {
        writer.AppendSummaryComment(call.Documentation);
        writer.AppendLine($"public virtual {GrpcCore}.{key}<{call.RequestType}, {call.ResponseType}> {call.Name}({GrpcCore}.Metadata? headers = null, System.DateTime? deadline = null, {CancellationToken} cancellationToken = default({CancellationToken}))");
        using (writer.WithBlock())
        {
            writer.AppendLine($"return {call.Name}(new {GrpcCore}.CallOptions(headers, deadline, cancellationToken));");
        }

        writer.AppendSummaryComment(call.Documentation);
        writer.AppendLine($"public virtual {GrpcCore}.{key}<{call.RequestType}, {call.ResponseType}> {call.Name}({GrpcCore}.CallOptions options)");
        using (writer.WithBlock())
        {
            writer.AppendLine($"return CallInvoker.{key}({methodMap[call.Name]}, null, options);");
        }
    }
    private void WriteClientMethod(CodeWriter writer, RpcCallSchemaModel call, Dictionary <string, string> methodMap)
    {
        switch (call.StreamingType)
        {
        case RpcStreamingType.Unary:
            this.WriteRequestParameterMethod(writer, "AsyncUnaryCall", call, methodMap);
            break;

        case RpcStreamingType.Client:
            this.WriteNoRequestParameterMethod(writer, "AsyncClientStreamingCall", call, methodMap);
            break;

        case RpcStreamingType.Server:
            this.WriteRequestParameterMethod(writer, "AsyncServerStreamingCall", call, methodMap);
            break;

        case RpcStreamingType.Bidirectional:
            this.WriteNoRequestParameterMethod(writer, "AsyncDuplexStreamingCall", call, methodMap);
            break;
        }
    }
    private string GetServerMethodSignature(RpcCallSchemaModel call)
    {
        const string TaskString = "System.Threading.Tasks.Task";

        switch (call.StreamingType)
        {
        case RpcStreamingType.Unary:
            return($"public abstract {TaskString}<{call.ResponseType}> {call.Name}({call.RequestType} request, {GrpcCore}.ServerCallContext callContext);");


        case RpcStreamingType.Client:
            return($"public abstract {TaskString}<{call.ResponseType}> {call.Name}({GrpcCore}.IAsyncStreamReader<{call.RequestType}> requestStream, {GrpcCore}.ServerCallContext callContext);");


        case RpcStreamingType.Server:
            return($"public abstract {TaskString} {call.Name}({call.RequestType} request, {GrpcCore}.IServerStreamWriter<{call.ResponseType}> responseStream, {GrpcCore}.ServerCallContext callContext);");


        case RpcStreamingType.Bidirectional:
            return($"public abstract {TaskString} {call.Name}({GrpcCore}.IAsyncStreamReader<{call.RequestType}> requestStream, {GrpcCore}.IServerStreamWriter<{call.ResponseType}> responseStream, {GrpcCore}.ServerCallContext callContext);");
        }

        throw new InvalidOperationException("Unrecognized streaming type: " + call.StreamingType);
    }
    private string GetServerHandlerDelegate(RpcCallSchemaModel call)
    {
        string methodType = GetGrpcMethodType(call.StreamingType);

        return($"new {GrpcCore}.{methodType}ServerMethod<{call.RequestType}, {call.ResponseType}>(serviceImpl.{call.Name})");
    }