// ------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version: 18.0.0.0
//  
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
namespace Azure.Iot.Operations.EnvoyGenerator
{
    using System.Linq;
    using Azure.Iot.Operations.CodeGeneration;
    using System;
    
    /// <summary>
    /// Class to produce the template output
    /// </summary>
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
    public partial class DotNetService : DotNetServiceBase
    {
        /// <summary>
        /// Create the template output
        /// </summary>
        public virtual string TransformText()
        {
 // Copyright (c) Microsoft Corporation. 
 // Licensed under the MIT License 
            this.Write("/* Code generated by Azure.Iot.Operations.ProtocolCompilerLib v");
            this.Write(this.ToStringHelper.ToStringWithCulture(System.Reflection.Assembly.GetExecutingAssembly().GetName().Version));
            this.Write("; DO NOT EDIT. */\r\n\r\n#nullable enable\r\n\r\nusing System;\r\nusing System.Collections." +
                    "Generic;\r\nusing System.Linq;\r\n");
 if (this.actionSpecs.Any() || this.propSpecs.Any() || this.eventSpec.Any()) { 
            this.Write("using System.Threading;\r\n");
 } 
            this.Write("using System.Threading.Tasks;\r\nusing Azure.Iot.Operations.Protocol.Models;\r\nusing" +
                    " Azure.Iot.Operations.Protocol;\r\nusing Azure.Iot.Operations.Protocol.RPC;\r\nusing" +
                    " Azure.Iot.Operations.Protocol.Telemetry;\r\nusing ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.commonNs.GetNamespaceName(TargetLanguage.CSharp, this.projectName)));
            this.Write(";\r\n\r\nnamespace ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.projectName));
            this.Write(".");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.genNamespace.GetNamespaceName(TargetLanguage.CSharp)));
            this.Write("\r\n{\r\n    [System.CodeDom.Compiler.GeneratedCode(\"Azure.Iot.Operations.ProtocolCom" +
                    "pilerLib\", \"");
            this.Write(this.ToStringHelper.ToStringWithCulture(System.Reflection.Assembly.GetExecutingAssembly().GetName().Version));
            this.Write("\")]\r\n    public static partial class ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.serviceName.GetTypeName(TargetLanguage.CSharp)));
            this.Write("\r\n    {\r\n");
 if (this.generateServer) { 
            this.Write("        public abstract partial class Service : IAsyncDisposable\r\n        {\r\n    " +
                    "        private ApplicationContext applicationContext;\r\n            private IMqt" +
                    "tPubSubClient mqttClient;\r\n");
 foreach (var actionSpec in this.actionSpecs) { 
            this.Write("            private readonly ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Executor.GetTypeName(TargetLanguage.CSharp)));
            this.Write(" ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Executor.GetVariableName(TargetLanguage.CSharp)));
            this.Write(";\r\n");
 } 
 foreach (var propSpec in this.propSpecs) { 
            this.Write("            private readonly ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Maintainer.GetTypeName(TargetLanguage.CSharp)));
            this.Write(".");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.readResponderName.GetTypeName(TargetLanguage.CSharp)));
            this.Write(" ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "read", "responder")));
            this.Write(";\r\n");
 if (propSpec.WriteReqSchema != null) { 
            this.Write("            private readonly ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Maintainer.GetTypeName(TargetLanguage.CSharp)));
            this.Write(".");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.writeResponderName.GetTypeName(TargetLanguage.CSharp)));
            this.Write(" ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "write", "responder")));
            this.Write(";\r\n");
 } 
 } 
 foreach (var telemEnvoyInfo in this.eventSpec) { 
            this.Write("            private readonly ");
            this.Write(this.ToStringHelper.ToStringWithCulture(telemEnvoyInfo.Sender.GetTypeName(TargetLanguage.CSharp)));
            this.Write(" ");
            this.Write(this.ToStringHelper.ToStringWithCulture(telemEnvoyInfo.Sender.GetVariableName(TargetLanguage.CSharp)));
            this.Write(";\r\n");
 } 
            this.Write(@"
            /// <summary>
            /// Construct a new instance of this service.
            /// </summary>
            /// <param name=""applicationContext"">The shared context for your application.</param>
            /// <param name=""mqttClient"">The MQTT client to use.</param>
            /// <param name=""topicTokenMap"">
            /// The topic token replacement map to use for all operations by default. Generally, this will include the token values
            /// for topic tokens that should be the same for the duration of this service's lifetime. Note that
            /// additional topic tokens can be specified per event message.
            /// </param>
            public Service(ApplicationContext applicationContext, IMqttPubSubClient mqttClient, Dictionary<string, string>? topicTokenMap = null)
            {
                this.applicationContext = applicationContext;
                this.mqttClient = mqttClient;

                string? clientId = this.mqttClient.ClientId;
                if (string.IsNullOrEmpty(clientId))
                {
                    throw new InvalidOperationException(""No MQTT client Id configured. Must connect to MQTT broker before invoking command."");
                }

");
 foreach (var actionSpec in this.actionSpecs) { 
            this.Write("                this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Executor.GetVariableName(TargetLanguage.CSharp)));
            this.Write(" = new ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Executor.GetTypeName(TargetLanguage.CSharp)));
            this.Write("(applicationContext, mqttClient) { OnCommandReceived = ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Name.GetMethodName(TargetLanguage.CSharp, "int")));
            this.Write(" };\r\n");
 } 
 foreach (var propSpec in this.propSpecs) { 
            this.Write("                this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "read", "responder")));
            this.Write(" = new ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Maintainer.GetTypeName(TargetLanguage.CSharp)));
            this.Write(".");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.readResponderName.GetTypeName(TargetLanguage.CSharp)));
            this.Write("(applicationContext, mqttClient) { OnCommandReceived = ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetMethodName(TargetLanguage.CSharp, "int", prefix: "read")));
            this.Write(" };\r\n");
 if (propSpec.WriteReqSchema != null) { 
            this.Write("                this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "write", "responder")));
            this.Write(" = new ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Maintainer.GetTypeName(TargetLanguage.CSharp)));
            this.Write(".");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.writeResponderName.GetTypeName(TargetLanguage.CSharp)));
            this.Write("(applicationContext, mqttClient) { OnCommandReceived = ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetMethodName(TargetLanguage.CSharp, "int", prefix: "write")));
            this.Write(" };\r\n");
 } 
 } 
 foreach (var telemEnvoyInfo in this.eventSpec) { 
            this.Write("                this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(telemEnvoyInfo.Sender.GetVariableName(TargetLanguage.CSharp)));
            this.Write(" = new ");
            this.Write(this.ToStringHelper.ToStringWithCulture(telemEnvoyInfo.Sender.GetTypeName(TargetLanguage.CSharp)));
            this.Write("(applicationContext, mqttClient);\r\n");
 } 
            this.Write("\r\n                if (topicTokenMap != null)\r\n                {\r\n                " +
                    "    foreach (string topicTokenKey in topicTokenMap.Keys)\r\n                    {\r" +
                    "\n");
 foreach (var actionSpec in this.actionSpecs) { 
            this.Write("                        this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Executor.GetVariableName(TargetLanguage.CSharp)));
            this.Write(".TopicTokenMap.TryAdd(\"ex:\" + topicTokenKey, topicTokenMap[topicTokenKey]);\r\n");
 } 
 foreach (var propSpec in this.propSpecs) { 
            this.Write("                        this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "read", "responder")));
            this.Write(".TopicTokenMap.TryAdd(\"ex:\" + topicTokenKey, topicTokenMap[topicTokenKey]);\r\n");
 if (propSpec.WriteReqSchema != null) { 
            this.Write("                        this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "write", "responder")));
            this.Write(".TopicTokenMap.TryAdd(\"ex:\" + topicTokenKey, topicTokenMap[topicTokenKey]);\r\n");
 } 
 } 
 foreach (var telemEnvoyInfo in this.eventSpec) { 
            this.Write("                        this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(telemEnvoyInfo.Sender.GetVariableName(TargetLanguage.CSharp)));
            this.Write(".TopicTokenMap.TryAdd(\"ex:\" + topicTokenKey, topicTokenMap[topicTokenKey]);\r\n");
 } 
            this.Write("                    }\r\n                }\r\n\r\n");
 foreach (var actionSpec in this.actionSpecs) { 
            this.Write("                this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Executor.GetVariableName(TargetLanguage.CSharp)));
            this.Write(".TopicTokenMap.TryAdd(\"");
            this.Write(this.ToStringHelper.ToStringWithCulture(MqttTopicTokens.ActionExecutorId));
            this.Write("\", clientId);\r\n");
 } 
 foreach (var propSpec in this.propSpecs) { 
            this.Write("                this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "read", "responder")));
            this.Write(".TopicTokenMap.TryAdd(\"");
            this.Write(this.ToStringHelper.ToStringWithCulture(MqttTopicTokens.PropertyMaintainerId));
            this.Write("\", clientId);\r\n");
 if (propSpec.WriteReqSchema != null) { 
            this.Write("                this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "write", "responder")));
            this.Write(".TopicTokenMap.TryAdd(\"");
            this.Write(this.ToStringHelper.ToStringWithCulture(MqttTopicTokens.PropertyMaintainerId));
            this.Write("\", clientId);\r\n");
 } 
 } 
            this.Write("            }\r\n");
 foreach (var actionSpec in this.actionSpecs) { 
            this.Write("\r\n            public ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Executor.GetTypeName(TargetLanguage.CSharp)));
            this.Write(" ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Executor.GetTypeName(TargetLanguage.CSharp)));
            this.Write(" { get => this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Executor.GetVariableName(TargetLanguage.CSharp)));
            this.Write("; }\r\n");
 } 
 foreach (var propSpec in this.propSpecs) { 
            this.Write("\r\n            public ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Maintainer.GetTypeName(TargetLanguage.CSharp)));
            this.Write(".");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.readResponderName.GetTypeName(TargetLanguage.CSharp)));
            this.Write(" ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetTypeName(TargetLanguage.CSharp, "read", "responder")));
            this.Write(" { get => this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "read", "responder")));
            this.Write("; }\r\n");
 if (propSpec.WriteReqSchema != null) { 
            this.Write("\r\n            public ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Maintainer.GetTypeName(TargetLanguage.CSharp)));
            this.Write(".");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.writeResponderName.GetTypeName(TargetLanguage.CSharp)));
            this.Write(" ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetTypeName(TargetLanguage.CSharp, "write", "responder")));
            this.Write(" { get => this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "write", "responder")));
            this.Write("; }\r\n");
 } 
 } 
 foreach (var telemEnvoyInfo in this.eventSpec) { 
            this.Write("\r\n            public ");
            this.Write(this.ToStringHelper.ToStringWithCulture(telemEnvoyInfo.Sender.GetTypeName(TargetLanguage.CSharp)));
            this.Write(" ");
            this.Write(this.ToStringHelper.ToStringWithCulture(telemEnvoyInfo.Sender.GetTypeName(TargetLanguage.CSharp)));
            this.Write(" { get => this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(telemEnvoyInfo.Sender.GetVariableName(TargetLanguage.CSharp)));
            this.Write("; }\r\n");
 } 
 foreach (var actionSpec in this.actionSpecs) { 
            this.Write("\r\n            public ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.defaultImpl ? "virtual" : "abstract"));
            this.Write(" ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.ExtRespType(actionSpec)));
            this.Write(" ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Name.GetMethodName(TargetLanguage.CSharp, "async")));
            this.Write("(");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.ReqParam(actionSpec)));
            this.Write("CommandRequestMetadata requestMetadata, CancellationToken cancellationToken)");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.defaultImpl ? "" : ";"));
            this.Write("\r\n");
 if (this.defaultImpl) { 
            this.Write("            {\r\n                return ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.EmptyResp(actionSpec)));
            this.Write(";\r\n            }\r\n");
 } 
 } 
 foreach (var propSpec in this.propSpecs) { 
            this.Write("\r\n            public abstract Task<ExtendedResponse<");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.PropSchema.GetTypeName(TargetLanguage.CSharp)));
            this.Write(">> ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetMethodName(TargetLanguage.CSharp, "async", prefix: "read")));
            this.Write("(CommandRequestMetadata requestMetadata, CancellationToken cancellationToken);\r\n");
 if (propSpec.WriteReqSchema != null) { 
            this.Write("\r\n            public abstract Task<CommandResponseMetadata?> ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetMethodName(TargetLanguage.CSharp, "async", prefix: "write")));
            this.Write("(");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.WriteReqSchema.GetTypeName(TargetLanguage.CSharp)));
            this.Write(" ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp)));
            this.Write(", CommandRequestMetadata requestMetadata, CancellationToken cancellationToken);\r\n" +
                    "");
 } 
 } 
 foreach (var telemEnvoyInfo in this.eventSpec) { 
            this.Write(@"
            /// <summary>
            /// Send telemetry.
            /// </summary>
            /// <param name=""telemetry"">The payload of the telemetry.</param>
            /// <param name=""metadata"">The metadata of the telemetry.</param>
            /// <param name=""additionalTopicTokenMap"">
            /// The topic token replacement map to use in addition to the topic token map provided in the constructor. If this map
            /// contains any keys that topic token map provided in the constructor also has, then values specified in this map will take precedence.
            /// </param>
            /// <param name=""qos"">The quality of service to send the telemetry with.</param>
            /// <param name=""telemetryTimeout"">How long the telemetry message will be available on the broker for a receiver to receive.</param>
            /// <param name=""cancellationToken"">Cancellation token.</param>
            public async Task ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.TelemMethodName(telemEnvoyInfo, "send", "async")));
            this.Write("(");
            this.Write(this.ToStringHelper.ToStringWithCulture(telemEnvoyInfo.Schema.GetTypeName(TargetLanguage.CSharp)));
            this.Write(@" telemetry, OutgoingTelemetryMetadata metadata, Dictionary<string, string>? additionalTopicTokenMap = null, MqttQualityOfServiceLevel qos = MqttQualityOfServiceLevel.AtLeastOnce, TimeSpan? telemetryTimeout = null, CancellationToken cancellationToken = default)
            {
                additionalTopicTokenMap ??= new();

                Dictionary<string, string> prefixedAdditionalTopicTokenMap = new();
                foreach (string key in additionalTopicTokenMap.Keys)
                {
                    prefixedAdditionalTopicTokenMap[""ex:"" + key] = additionalTopicTokenMap[key];
                }
                await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(telemEnvoyInfo.Sender.GetVariableName(TargetLanguage.CSharp)));
            this.Write(".SendTelemetryAsync(telemetry, metadata, prefixedAdditionalTopicTokenMap, qos, te" +
                    "lemetryTimeout, cancellationToken);\r\n            }\r\n");
 } 
 if (this.actionSpecs.Any() || this.propSpecs.Any()) { 
            this.Write(@"
            /// <summary>
            /// Begin accepting command invocations for all command executors.
            /// </summary>
            /// <param name=""preferredDispatchConcurrency"">The dispatch concurrency count for the command response cache to use.</param>
            /// <param name=""cancellationToken"">Cancellation token.</param>
            public async Task StartAsync(int? preferredDispatchConcurrency = null, CancellationToken cancellationToken = default)
            {
                string? clientId = this.mqttClient.ClientId;
                if (string.IsNullOrEmpty(clientId))
                {
                    throw new InvalidOperationException(""No MQTT client Id configured. Must connect to MQTT broker before starting service."");
                }

                await Task.WhenAll(
");
 foreach (var actionSpec in this.actionSpecs) { 
            this.Write("                    this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Executor.GetVariableName(TargetLanguage.CSharp)));
            this.Write(".StartAsync(preferredDispatchConcurrency, cancellationToken)");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.IsLast(actionSpec) ? ").ConfigureAwait(false);" : ","));
            this.Write("\r\n");
 } 
 foreach (var propSpec in this.propSpecs) { 
            this.Write("                    this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "read", "responder")));
            this.Write(".StartAsync(preferredDispatchConcurrency, cancellationToken)");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.IsLast(propSpec) && propSpec.WriteReqSchema == null ? ").ConfigureAwait(false);" : ","));
            this.Write("\r\n");
 if (propSpec.WriteReqSchema != null) { 
            this.Write("                    this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "write", "responder")));
            this.Write(".StartAsync(preferredDispatchConcurrency, cancellationToken)");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.IsLast(propSpec) ? ").ConfigureAwait(false);" : ","));
            this.Write("\r\n");
 } 
 } 
            this.Write("            }\r\n\r\n            public async Task StopAsync(CancellationToken cancel" +
                    "lationToken = default)\r\n            {\r\n                await Task.WhenAll(\r\n");
 foreach (var actionSpec in this.actionSpecs) { 
            this.Write("                    this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Executor.GetVariableName(TargetLanguage.CSharp)));
            this.Write(".StopAsync(cancellationToken)");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.IsLast(actionSpec) ? ").ConfigureAwait(false);" : ","));
            this.Write("\r\n");
 } 
 foreach (var propSpec in this.propSpecs) { 
            this.Write("                    this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "read", "responder")));
            this.Write(".StopAsync(cancellationToken)");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.IsLast(propSpec) && propSpec.WriteReqSchema == null ? ").ConfigureAwait(false);" : ","));
            this.Write("\r\n");
 if (propSpec.WriteReqSchema != null) { 
            this.Write("                    this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "write", "responder")));
            this.Write(".StopAsync(cancellationToken)");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.IsLast(propSpec) ? ").ConfigureAwait(false);" : ","));
            this.Write("\r\n");
 } 
 } 
            this.Write("            }\r\n");
 } 
 foreach (var actionSpec in this.actionSpecs) { 
            this.Write("\r\n            private async Task<ExtendedResponse<");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.SchemaType(actionSpec.ResponseSchema, actionSpec.SerializerEmptyType)));
            this.Write(">> ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Name.GetMethodName(TargetLanguage.CSharp, "int")));
            this.Write("(ExtendedRequest<");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.SchemaType(actionSpec.RequestSchema, actionSpec.SerializerEmptyType)));
            this.Write("> req, CancellationToken cancellationToken)\r\n            {\r\n");
 if (actionSpec.ErrorResultName != null) { 
            this.Write("                try\r\n                {\r\n                    ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.IntLValue(actionSpec)));
            this.Write("await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Name.GetMethodName(TargetLanguage.CSharp, "async")));
            this.Write("(");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.ReqArgs(actionSpec, "req")));
            this.Write(", cancellationToken);\r\n\r\n                    return new ExtendedResponse<");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.SchemaType(actionSpec.ResponseSchema, actionSpec.SerializerEmptyType)));
            this.Write(">\r\n                    {\r\n                        Response = new ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.SchemaType(actionSpec.ResponseSchema, actionSpec.SerializerEmptyType)));
            this.Write("\r\n                        {\r\n");
 if (actionSpec.NormalResultName != null) { 
            this.Write("                            ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.NormalResultName.GetFieldName(TargetLanguage.CSharp)));
            this.Write(" = extended.Response,\r\n");
 } else { 
 foreach (CodeName normalResultName in actionSpec.NormalResultNames) { 
            this.Write("                            ");
            this.Write(this.ToStringHelper.ToStringWithCulture(normalResultName.GetFieldName(TargetLanguage.CSharp)));
            this.Write(" = extended.Response.");
            this.Write(this.ToStringHelper.ToStringWithCulture(normalResultName.GetFieldName(TargetLanguage.CSharp)));
            this.Write(",\r\n");
 } 
 } 
            this.Write("                        },\r\n                        ResponseMetadata = extended.R" +
                    "esponseMetadata,\r\n                    };\r\n                }\r\n                cat" +
                    "ch (");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.ErrorResultSchema.GetTypeName(TargetLanguage.CSharp, "exception")));
            this.Write(" intEx)\r\n                {\r\n                    ExtendedResponse<");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.SchemaType(actionSpec.ResponseSchema, actionSpec.SerializerEmptyType)));
            this.Write("> extendedResponse = ExtendedResponse<");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.SchemaType(actionSpec.ResponseSchema, actionSpec.SerializerEmptyType)));
            this.Write(">.CreateFromResponse(new ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.SchemaType(actionSpec.ResponseSchema, actionSpec.SerializerEmptyType)));
            this.Write(" { ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.ErrorResultName.GetFieldName(TargetLanguage.CSharp)));
            this.Write(" = intEx.");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.ErrorResultSchema.GetFieldName(TargetLanguage.CSharp)));
            this.Write(" });\r\n");
 if (actionSpec.ErrorCodeName != null) { 
            this.Write("\r\n                    if (intEx.TryGetApplicationError(out ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.ErrorCodeSchema.GetTypeName(TargetLanguage.CSharp)));
            this.Write("? ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.ErrorCodeName.GetVariableName(TargetLanguage.CSharp)));
            this.Write(", out ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.GetInfoSchema(actionSpec.ErrorInfoSchema)));
            this.Write("? ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.GetInfoName(actionSpec.ErrorInfoName)));
            this.Write("))\r\n                    {\r\n                        extendedResponse = extendedRes" +
                    "ponse.WithApplicationError((");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.ErrorCodeSchema.GetTypeName(TargetLanguage.CSharp)));
            this.Write(")");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.ErrorCodeName.GetVariableName(TargetLanguage.CSharp)));
            this.Write(", ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.GetInfoName(actionSpec.ErrorInfoName)));
            this.Write(");\r\n                    }\r\n\r\n");
 } 
            this.Write("                    return extendedResponse;\r\n                }\r\n");
 } else { 
            this.Write("                ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.IntLValue(actionSpec)));
            this.Write("await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Name.GetMethodName(TargetLanguage.CSharp, "async")));
            this.Write("(");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.ReqArgs(actionSpec, "req")));
            this.Write(", cancellationToken);\r\n                return new ExtendedResponse<");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.SchemaType(actionSpec.ResponseSchema, actionSpec.SerializerEmptyType)));
            this.Write("> { ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.IntRValue(actionSpec)));
            this.Write("};\r\n");
 } 
            this.Write("            }\r\n");
 } 
 foreach (var propSpec in this.propSpecs) { 
            this.Write("\r\n            private async Task<ExtendedResponse<");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.ReadRespSchema.GetTypeName(TargetLanguage.CSharp)));
            this.Write(">> ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetMethodName(TargetLanguage.CSharp, "int", prefix: "read")));
            this.Write("(ExtendedRequest<");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.ReadSerializerEmptyType.GetTypeName(TargetLanguage.CSharp)));
            this.Write("> req, CancellationToken cancellationToken)\r\n            {\r\n");
 if (propSpec.ReadErrorName != null) { 
            this.Write("                try\r\n                {\r\n                    ExtendedResponse<");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.PropSchema.GetTypeName(TargetLanguage.CSharp)));
            this.Write("> extended = await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetMethodName(TargetLanguage.CSharp, "async", prefix: "read")));
            this.Write("(req.RequestMetadata!, cancellationToken);\r\n\r\n                    return new Exte" +
                    "ndedResponse<");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.ReadRespSchema.GetTypeName(TargetLanguage.CSharp)));
            this.Write(">\r\n                    {\r\n                        Response = new ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.ReadRespSchema.GetTypeName(TargetLanguage.CSharp)));
            this.Write(" { ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.PropValueName.GetFieldName(TargetLanguage.CSharp)));
            this.Write(" = extended.Response");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.IsAggregate ? "" : $".{propSpec.PropValueName.GetFieldName(TargetLanguage.CSharp)}"));
            this.Write(" },\r\n                        ResponseMetadata = extended.ResponseMetadata,\r\n     " +
                    "               };\r\n                }\r\n                catch (");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.ReadErrorSchema.GetTypeName(TargetLanguage.CSharp, "exception")));
            this.Write(" intEx)\r\n                {\r\n                    ExtendedResponse<");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.SchemaType(propSpec.ReadRespSchema, propSpec.ReadSerializerEmptyType)));
            this.Write("> extendedResponse = ExtendedResponse<");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.SchemaType(propSpec.ReadRespSchema, propSpec.ReadSerializerEmptyType)));
            this.Write(">.CreateFromResponse(new ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.SchemaType(propSpec.ReadRespSchema, propSpec.ReadSerializerEmptyType)));
            this.Write(" { ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.ReadErrorName.GetFieldName(TargetLanguage.CSharp)));
            this.Write(" = intEx.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.ReadErrorSchema.GetFieldName(TargetLanguage.CSharp)));
            this.Write(" });\r\n                    return extendedResponse;\r\n                }\r\n");
 } else { 
            this.Write("                return await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetMethodName(TargetLanguage.CSharp, "async", prefix: "read")));
            this.Write("(req.RequestMetadata!, cancellationToken);\r\n");
 } 
            this.Write("            }\r\n");
 if (propSpec.WriteReqSchema != null) { 
            this.Write("\r\n            private async Task<ExtendedResponse<");
            this.Write(this.ToStringHelper.ToStringWithCulture((propSpec.WriteRespSchema ?? propSpec.WriteSerializerEmptyType).GetTypeName(TargetLanguage.CSharp)));
            this.Write(">> ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetMethodName(TargetLanguage.CSharp, "int", prefix: "write")));
            this.Write("(ExtendedRequest<");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.WriteReqSchema.GetTypeName(TargetLanguage.CSharp)));
            this.Write("> req, CancellationToken cancellationToken)\r\n            {\r\n");
 if (propSpec.WriteRespSchema != null) { 
            this.Write("                try\r\n                {\r\n                    CommandResponseMetada" +
                    "ta? respMetadata = await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetMethodName(TargetLanguage.CSharp, "async", prefix: "write")));
            this.Write("(req.Request!, req.RequestMetadata!, cancellationToken);\r\n\r\n                    r" +
                    "eturn new ExtendedResponse<");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.WriteRespSchema.GetTypeName(TargetLanguage.CSharp)));
            this.Write(">\r\n                    {\r\n                        Response = new ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.WriteRespSchema.GetTypeName(TargetLanguage.CSharp)));
            this.Write("\r\n                        {\r\n                            ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.WriteErrorName.GetFieldName(TargetLanguage.CSharp)));
            this.Write(" = null,\r\n                        },\r\n                        ResponseMetadata = " +
                    "respMetadata,\r\n                    };\r\n                }\r\n                catch " +
                    "(");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.WriteErrorSchema.GetTypeName(TargetLanguage.CSharp, "exception")));
            this.Write(" intEx)\r\n                {\r\n                    ExtendedResponse<");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.SchemaType(propSpec.WriteRespSchema, propSpec.WriteSerializerEmptyType)));
            this.Write("> extendedResponse = ExtendedResponse<");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.SchemaType(propSpec.WriteRespSchema, propSpec.WriteSerializerEmptyType)));
            this.Write(">.CreateFromResponse(new ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.SchemaType(propSpec.WriteRespSchema, propSpec.WriteSerializerEmptyType)));
            this.Write(" { ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.WriteErrorName.GetFieldName(TargetLanguage.CSharp)));
            this.Write(" = intEx.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.WriteErrorSchema.GetFieldName(TargetLanguage.CSharp)));
            this.Write(" });\r\n                    return extendedResponse;\r\n                }\r\n");
 } else { 
            this.Write("                CommandResponseMetadata? respMetadata = await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetMethodName(TargetLanguage.CSharp, "async", prefix: "write")));
            this.Write("(req.Request!, req.RequestMetadata!, cancellationToken);\r\n                return " +
                    "new ExtendedResponse<");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.WriteSerializerEmptyType.GetTypeName(TargetLanguage.CSharp)));
            this.Write(">\r\n                {\r\n                    Response = new ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.WriteSerializerEmptyType.GetTypeName(TargetLanguage.CSharp)));
            this.Write("(),\r\n                    ResponseMetadata = respMetadata,\r\n                };\r\n");
 } 
            this.Write("            }\r\n");
 } 
 } 
            this.Write("\r\n            public async ValueTask DisposeAsync()\r\n            {\r\n");
 foreach (var actionSpec in this.actionSpecs) { 
            this.Write("                await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Executor.GetVariableName(TargetLanguage.CSharp)));
            this.Write(".DisposeAsync().ConfigureAwait(false);\r\n");
 } 
 foreach (var propSpec in this.propSpecs) { 
            this.Write("                await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "read", "responder")));
            this.Write(".DisposeAsync().ConfigureAwait(false);\r\n");
 if (propSpec.WriteReqSchema != null) { 
            this.Write("                await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "write", "responder")));
            this.Write(".DisposeAsync().ConfigureAwait(false); \r\n");
 } 
 } 
 foreach (var telemEnvoyInfo in this.eventSpec) { 
            this.Write("                await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(telemEnvoyInfo.Sender.GetVariableName(TargetLanguage.CSharp)));
            this.Write(".DisposeAsync().ConfigureAwait(false);\r\n");
 } 
            this.Write("            }\r\n\r\n            public async ValueTask DisposeAsync(bool disposing, " +
                    "CancellationToken cancellationToken = default)\r\n            {\r\n");
 foreach (var actionSpec in this.actionSpecs) { 
            this.Write("                await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Executor.GetVariableName(TargetLanguage.CSharp)));
            this.Write(".DisposeAsync(disposing, cancellationToken).ConfigureAwait(false);\r\n");
 } 
 foreach (var propSpec in this.propSpecs) { 
            this.Write("                await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "read", "responder")));
            this.Write(".DisposeAsync(disposing, cancellationToken).ConfigureAwait(false);\r\n");
 if (propSpec.WriteReqSchema != null) { 
            this.Write("                await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "write", "responder")));
            this.Write(".DisposeAsync(disposing, cancellationToken).ConfigureAwait(false); \r\n");
 } 
 } 
 foreach (var telemEnvoyInfo in this.eventSpec) { 
            this.Write("                await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(telemEnvoyInfo.Sender.GetVariableName(TargetLanguage.CSharp)));
            this.Write(".DisposeAsync(disposing, cancellationToken).ConfigureAwait(false);\r\n");
 } 
            this.Write("            }\r\n        }\r\n");
 } 
 if (this.generateServer && this.generateClient) { 
            this.Write("\r\n");
 } 
 if (this.generateClient) { 
            this.Write("        public abstract partial class Client");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.actionSpecs.Any() || this.propSpecs.Any() ? " : IAsyncDisposable" : ""));
            this.Write("\r\n        {\r\n            private ApplicationContext applicationContext;\r\n        " +
                    "    private IMqttPubSubClient mqttClient;\r\n");
 foreach (var actionSpec in this.actionSpecs) { 
            this.Write("            private readonly ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Invoker.GetTypeName(TargetLanguage.CSharp)));
            this.Write(" ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Invoker.GetVariableName(TargetLanguage.CSharp)));
            this.Write(";\r\n");
 } 
 foreach (var propSpec in this.propSpecs) { 
            this.Write("            private readonly ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Consumer.GetTypeName(TargetLanguage.CSharp)));
            this.Write(".");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.readRequesterName.GetTypeName(TargetLanguage.CSharp)));
            this.Write(" ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "read", "requester")));
            this.Write(";\r\n");
 if (propSpec.WriteReqSchema != null) { 
            this.Write("            private readonly ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Consumer.GetTypeName(TargetLanguage.CSharp)));
            this.Write(".");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.writeRequesterName.GetTypeName(TargetLanguage.CSharp)));
            this.Write(" ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "write", "requester")));
            this.Write(";\r\n");
 } 
 } 
 foreach (var telemEnvoyInfo in this.eventSpec) { 
            this.Write("            private readonly ");
            this.Write(this.ToStringHelper.ToStringWithCulture(telemEnvoyInfo.Receiver.GetTypeName(TargetLanguage.CSharp)));
            this.Write(" ");
            this.Write(this.ToStringHelper.ToStringWithCulture(telemEnvoyInfo.Receiver.GetVariableName(TargetLanguage.CSharp)));
            this.Write(";\r\n");
 } 
            this.Write(@"
            /// <summary>
            /// Construct a new instance of this client.
            /// </summary>
            /// <param name=""applicationContext"">The shared context for your application.</param>
            /// <param name=""mqttClient"">The MQTT client to use.</param>
            /// <param name=""topicTokenMap"">
            /// The topic token replacement map to use for all operations by default. Generally, this will include the token values
            /// for topic tokens that should be the same for the duration of this client's lifetime.
            /// </param>
            public Client(ApplicationContext applicationContext, IMqttPubSubClient mqttClient, Dictionary<string, string>? topicTokenMap = null)
            {
                this.applicationContext = applicationContext;
                this.mqttClient = mqttClient;

");
 foreach (var actionSpec in this.actionSpecs) { 
            this.Write("                this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Invoker.GetVariableName(TargetLanguage.CSharp)));
            this.Write(" = new ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Invoker.GetTypeName(TargetLanguage.CSharp)));
            this.Write("(applicationContext, mqttClient);\r\n");
 } 
 foreach (var propSpec in this.propSpecs) { 
            this.Write("                this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "read", "requester")));
            this.Write(" = new ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Consumer.GetTypeName(TargetLanguage.CSharp)));
            this.Write(".");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.readRequesterName.GetTypeName(TargetLanguage.CSharp)));
            this.Write("(applicationContext, mqttClient);\r\n");
 if (propSpec.WriteReqSchema != null) { 
            this.Write("                this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "write", "requester")));
            this.Write(" = new ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Consumer.GetTypeName(TargetLanguage.CSharp)));
            this.Write(".");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.writeRequesterName.GetTypeName(TargetLanguage.CSharp)));
            this.Write("(applicationContext, mqttClient);\r\n");
 } 
 } 
 foreach (var telemEnvoyInfo in this.eventSpec) { 
            this.Write("                this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(telemEnvoyInfo.Receiver.GetVariableName(TargetLanguage.CSharp)));
            this.Write(" = new ");
            this.Write(this.ToStringHelper.ToStringWithCulture(telemEnvoyInfo.Receiver.GetTypeName(TargetLanguage.CSharp)));
            this.Write("(applicationContext, mqttClient) { OnTelemetryReceived = this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.TelemMethodName(telemEnvoyInfo, "receive")));
            this.Write(" };\r\n");
 } 
            this.Write("\r\n                if (topicTokenMap != null)\r\n                {\r\n                " +
                    "    foreach (string topicTokenKey in topicTokenMap.Keys)\r\n                    {\r" +
                    "\n");
 foreach (var actionSpec in this.actionSpecs) { 
            this.Write("                        this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Invoker.GetVariableName(TargetLanguage.CSharp)));
            this.Write(".TopicTokenMap.TryAdd(\"ex:\" + topicTokenKey, topicTokenMap[topicTokenKey]);\r\n");
 } 
 foreach (var propSpec in this.propSpecs) { 
            this.Write("                        this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "read", "requester")));
            this.Write(".TopicTokenMap.TryAdd(\"ex:\" + topicTokenKey, topicTokenMap[topicTokenKey]);\r\n");
 if (propSpec.WriteReqSchema != null) { 
            this.Write("                        this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "write", "requester")));
            this.Write(".TopicTokenMap.TryAdd(\"ex:\" + topicTokenKey, topicTokenMap[topicTokenKey]);\r\n");
 } 
 } 
 foreach (var telemEnvoyInfo in this.eventSpec) { 
            this.Write("                        this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(telemEnvoyInfo.Receiver.GetVariableName(TargetLanguage.CSharp)));
            this.Write(".TopicTokenMap.TryAdd(\"ex:\" + topicTokenKey, topicTokenMap[topicTokenKey]);\r\n");
 } 
            this.Write("                    }\r\n                }\r\n            }\r\n");
 foreach (var actionSpec in this.actionSpecs) { 
            this.Write("\r\n            public ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Invoker.GetTypeName(TargetLanguage.CSharp)));
            this.Write(" ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Invoker.GetTypeName(TargetLanguage.CSharp)));
            this.Write(" { get => this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Invoker.GetVariableName(TargetLanguage.CSharp)));
            this.Write("; }\r\n");
 } 
 foreach (var propSpec in this.propSpecs) { 
            this.Write("\r\n            public ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Consumer.GetTypeName(TargetLanguage.CSharp)));
            this.Write(".");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.readRequesterName.GetTypeName(TargetLanguage.CSharp)));
            this.Write(" ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetTypeName(TargetLanguage.CSharp, "read", "requester")));
            this.Write(" { get => this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "read", "requester")));
            this.Write("; }\r\n");
 if (propSpec.WriteReqSchema != null) { 
            this.Write("\r\n            public ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Consumer.GetTypeName(TargetLanguage.CSharp)));
            this.Write(".");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.writeRequesterName.GetTypeName(TargetLanguage.CSharp)));
            this.Write(" ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetTypeName(TargetLanguage.CSharp, "write", "requester")));
            this.Write(" { get => this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "write", "requester")));
            this.Write("; }\r\n");
 } 
 } 
 foreach (var telemEnvoyInfo in this.eventSpec) { 
            this.Write("\r\n            public ");
            this.Write(this.ToStringHelper.ToStringWithCulture(telemEnvoyInfo.Receiver.GetTypeName(TargetLanguage.CSharp)));
            this.Write(" ");
            this.Write(this.ToStringHelper.ToStringWithCulture(telemEnvoyInfo.Receiver.GetTypeName(TargetLanguage.CSharp)));
            this.Write(" { get => this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(telemEnvoyInfo.Receiver.GetVariableName(TargetLanguage.CSharp)));
            this.Write("; }\r\n");
 } 
 foreach (var telemEnvoyInfo in this.eventSpec) { 
            this.Write("\r\n            public ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.defaultImpl ? "virtual" : "abstract"));
            this.Write(" Task ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.TelemMethodName(telemEnvoyInfo, "receive")));
            this.Write("(string senderId, ");
            this.Write(this.ToStringHelper.ToStringWithCulture(telemEnvoyInfo.Schema.GetTypeName(TargetLanguage.CSharp)));
            this.Write(" telemetry, IncomingTelemetryMetadata metadata)");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.defaultImpl ? "" : ";"));
            this.Write("\r\n");
 if (this.defaultImpl) { 
            this.Write("            {\r\n                return Task.CompletedTask;\r\n            }\r\n");
 } 
 } 
 foreach (var actionSpec in this.actionSpecs) { 
            this.Write("\r\n            /// <summary>\r\n            /// Invoke a command.\r\n            /// <" +
                    "/summary>\r\n");
 if (actionSpec.DoesTargetExecutor) { 
            this.Write("            /// <param name=\"executorId\">The identifier of the executor targeted " +
                    "by this command request.</param>\r\n");
 } 
 if (actionSpec.RequestSchema != null) { 
            this.Write("            /// <param name=\"request\">The data for this command request.</param>\r" +
                    "\n");
 } 
            this.Write(@"            /// <param name=""requestMetadata"">The metadata for this command request.</param>
            /// <param name=""additionalTopicTokenMap"">
            /// The topic token replacement map to use in addition to the topic tokens specified in the constructor. If this map
            /// contains any keys that the topic tokens specified in the constructor also has, then values specified in this map will take precedence.
            /// </param>
            /// <param name=""commandTimeout"">How long the command will be available on the broker for an executor to receive.</param>
            /// <param name=""cancellationToken"">Cancellation token.</param>
            /// <returns>The command response.</returns>
            public ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.CallAsyncType(actionSpec)));
            this.Write(" ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Name.GetMethodName(TargetLanguage.CSharp, "async")));
            this.Write("(");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.ExecParam(actionSpec)));
            this.Write(this.ToStringHelper.ToStringWithCulture(this.ReqParam(actionSpec)));
            this.Write(@"CommandRequestMetadata? requestMetadata = null, Dictionary<string, string>? additionalTopicTokenMap = null, TimeSpan? commandTimeout = default, CancellationToken cancellationToken = default)
            {
                string? clientId = this.mqttClient.ClientId;
                if (string.IsNullOrEmpty(clientId))
                {
                    throw new InvalidOperationException(""No MQTT client Id configured. Must connect to MQTT broker before invoking command."");
                }

                CommandRequestMetadata metadata = requestMetadata ?? new CommandRequestMetadata();
                additionalTopicTokenMap ??= new();

                Dictionary<string, string> prefixedAdditionalTopicTokenMap = new();
                foreach (string key in additionalTopicTokenMap.Keys)
                {
                    prefixedAdditionalTopicTokenMap[""ex:"" + key] = additionalTopicTokenMap[key];
                }

                prefixedAdditionalTopicTokenMap[""invokerClientId""] = clientId;
");
 if (actionSpec.DoesTargetExecutor) { 
            this.Write("                prefixedAdditionalTopicTokenMap[\"executorId\"] = executorId;\r\n");
 } 
            this.Write("\r\n                return new ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.CallAsyncType(actionSpec)));
            this.Write("(this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.IntMethod(actionSpec)));
            this.Write("(");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.RequestSchema != null ? $"request" : actionSpec.SerializerEmptyType.GetAllocator(TargetLanguage.CSharp)));
            this.Write(", metadata, prefixedAdditionalTopicTokenMap, commandTimeout, cancellationToken), " +
                    "metadata.CorrelationId);\r\n            }\r\n");
 } 
 foreach (var propSpec in this.propSpecs) { 
            this.Write("\r\n            public ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.CallAsyncType(propSpec)));
            this.Write(" ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetMethodName(TargetLanguage.CSharp, "async", prefix: "read")));
            this.Write("(");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.ReadMaintParam(propSpec)));
            this.Write(@"CommandRequestMetadata? requestMetadata = null, Dictionary<string, string>? additionalTopicTokenMap = null, TimeSpan? commandTimeout = default, CancellationToken cancellationToken = default)
            {
                string? clientId = this.mqttClient.ClientId;
                if (string.IsNullOrEmpty(clientId))
                {
                    throw new InvalidOperationException(""No MQTT client Id configured. Must connect to MQTT broker before requesting to read property."");
                }

                CommandRequestMetadata metadata = requestMetadata ?? new CommandRequestMetadata();
                additionalTopicTokenMap ??= new();

                Dictionary<string, string> prefixedAdditionalTopicTokenMap = new();
                foreach (string key in additionalTopicTokenMap.Keys)
                {
                    prefixedAdditionalTopicTokenMap[""ex:"" + key] = additionalTopicTokenMap[key];
                }

                prefixedAdditionalTopicTokenMap[""consumerClientId""] = clientId;
");
 if (propSpec.DoesReadTargetMaintainer) { 
            this.Write("                prefixedAdditionalTopicTokenMap[\"maintainerId\"] = maintainerId;\r\n" +
                    "");
 } 
            this.Write("\r\n                return new ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.CallAsyncType(propSpec)));
            this.Write("(this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.IntReadMethod(propSpec)));
            this.Write("(");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.ReadSerializerEmptyType.GetAllocator(TargetLanguage.CSharp)));
            this.Write(", metadata, prefixedAdditionalTopicTokenMap, commandTimeout, cancellationToken), " +
                    "metadata.CorrelationId);\r\n            }\r\n");
 if (propSpec.WriteReqSchema != null) { 
            this.Write("\r\n            public RpcCallAsync<");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.ReadSerializerEmptyType.GetTypeName(TargetLanguage.CSharp)));
            this.Write("> ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetMethodName(TargetLanguage.CSharp, "async", prefix: "write")));
            this.Write("(");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.WriteMaintParam(propSpec)));
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.WriteReqSchema.GetTypeName(TargetLanguage.CSharp)));
            this.Write(@" request, CommandRequestMetadata? requestMetadata = null, Dictionary<string, string>? additionalTopicTokenMap = null, TimeSpan? commandTimeout = default, CancellationToken cancellationToken = default)
            {
                string? clientId = this.mqttClient.ClientId;
                if (string.IsNullOrEmpty(clientId))
                {
                    throw new InvalidOperationException(""No MQTT client Id configured. Must connect to MQTT broker before requesting to write property."");
                }

                CommandRequestMetadata metadata = requestMetadata ?? new CommandRequestMetadata();
                additionalTopicTokenMap ??= new();

                Dictionary<string, string> prefixedAdditionalTopicTokenMap = new();
                foreach (string key in additionalTopicTokenMap.Keys)
                {
                    prefixedAdditionalTopicTokenMap[""ex:"" + key] = additionalTopicTokenMap[key];
                }

                prefixedAdditionalTopicTokenMap[""consumerClientId""] = clientId;
");
 if (propSpec.DoesWriteTargetMaintainer) { 
            this.Write("                prefixedAdditionalTopicTokenMap[\"maintainerId\"] = maintainerId;\r\n" +
                    "");
 } 
            this.Write("\r\n                return new RpcCallAsync<");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.WriteSerializerEmptyType.GetTypeName(TargetLanguage.CSharp)));
            this.Write(">(this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.IntWriteMethod(propSpec)));
            this.Write("(request, metadata, prefixedAdditionalTopicTokenMap, commandTimeout, cancellation" +
                    "Token), metadata.CorrelationId);\r\n            }\r\n");
 } 
 } 
 if (this.eventSpec.Any()) { 
            this.Write(@"
            /// <summary>
            /// Begin accepting telemetry for all telemetry receivers.
            /// </summary>
            /// <param name=""cancellationToken"">Cancellation token.</param>
            public async Task StartAsync(CancellationToken cancellationToken = default)
            {
                await Task.WhenAll(
");
 foreach (var telemEnvoyInfo in this.eventSpec) { 
            this.Write("                    this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(telemEnvoyInfo.Receiver.GetVariableName(TargetLanguage.CSharp)));
            this.Write(".StartAsync(cancellationToken)");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.IsLast(telemEnvoyInfo) ? ").ConfigureAwait(false);" : ","));
            this.Write("\r\n");
 } 
            this.Write("            }\r\n");
 } 
 if (this.eventSpec.Any() || this.actionSpecs.Any() || this.propSpecs.Any()) { 
            this.Write(@"
            /// <summary>
            /// Stop accepting telemetry for all telemetry receivers and make all command invokers unsubscribe from command topics.
            /// </summary>
            /// <param name=""cancellationToken"">Cancellation token.</param>
            public async Task StopAsync(CancellationToken cancellationToken = default)
            {
                await Task.WhenAll(
");
 foreach (var telemEnvoyInfo in this.eventSpec) { 
            this.Write("                    this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(telemEnvoyInfo.Receiver.GetVariableName(TargetLanguage.CSharp)));
            this.Write(".StopAsync(cancellationToken)");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.IsLast(telemEnvoyInfo) && !this.actionSpecs.Any() && !this.propSpecs.Any() ? ").ConfigureAwait(false);" : ","));
            this.Write("\r\n");
 } 
 foreach (var actionSpec in this.actionSpecs) { 
            this.Write("                    this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Invoker.GetVariableName(TargetLanguage.CSharp)));
            this.Write(".StopAsync(cancellationToken)");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.IsLast(actionSpec) ? ").ConfigureAwait(false);" : ","));
            this.Write("\r\n");
 } 
 foreach (var propSpec in this.propSpecs) { 
            this.Write("                    this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "read", "requester")));
            this.Write(".StopAsync(cancellationToken)");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.IsLast(propSpec) && propSpec.WriteReqSchema == null ? ").ConfigureAwait(false);" : ","));
            this.Write("\r\n");
 if (propSpec.WriteReqSchema != null) { 
            this.Write("                    this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "write", "requester")));
            this.Write(".StopAsync(cancellationToken)");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.IsLast(propSpec) ? ").ConfigureAwait(false);" : ","));
            this.Write("\r\n");
 } 
 } 
            this.Write("            }\r\n");
 } 
 foreach (var actionSpec in this.actionSpecs) { 
 if (actionSpec.ErrorResultName != null) { 
            this.Write("\r\n            private async Task<ExtendedResponse<");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.SchemaType(actionSpec.NormalResultSchema, actionSpec.SerializerEmptyType)));
            this.Write(">> ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Name.GetMethodName(TargetLanguage.CSharp, "int")));
            this.Write("(");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.SchemaType(actionSpec.RequestSchema, actionSpec.SerializerEmptyType)));
            this.Write(" request, CommandRequestMetadata? requestMetadata, Dictionary<string, string>? pr" +
                    "efixedAdditionalTopicTokenMap, TimeSpan? commandTimeout, CancellationToken cance" +
                    "llationToken)\r\n            {\r\n                ExtendedResponse<");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.SchemaType(actionSpec.ResponseSchema, actionSpec.SerializerEmptyType)));
            this.Write("> extended = await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Invoker.GetVariableName(TargetLanguage.CSharp)));
            this.Write(".InvokeCommandAsync(request, requestMetadata, prefixedAdditionalTopicTokenMap, co" +
                    "mmandTimeout, cancellationToken);\r\n\r\n                if (extended.Response.");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.ErrorResultName.GetFieldName(TargetLanguage.CSharp)));
            this.Write(" != null)\r\n                {\r\n                    ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.ErrorResultSchema.GetTypeName(TargetLanguage.CSharp, "exception")));
            this.Write(" ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.ErrorResultSchema.GetVariableName(TargetLanguage.CSharp, "exception")));
            this.Write(" = new ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.ErrorResultSchema.GetTypeName(TargetLanguage.CSharp, "exception")));
            this.Write("(extended.Response.");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.ErrorResultName.GetFieldName(TargetLanguage.CSharp)));
            this.Write(");\r\n");
 if (actionSpec.ErrorCodeName != null) { 
            this.Write("\r\n                    if (extended.TryGetApplicationError(out ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.ErrorCodeSchema.GetTypeName(TargetLanguage.CSharp)));
            this.Write("? ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.ErrorCodeName.GetVariableName(TargetLanguage.CSharp)));
            this.Write(", out ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.GetInfoSchema(actionSpec.ErrorInfoSchema)));
            this.Write("? ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.GetInfoName(actionSpec.ErrorInfoName)));
            this.Write("))\r\n                    {\r\n                        ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.ErrorResultSchema.GetVariableName(TargetLanguage.CSharp, "exception")));
            this.Write(" = ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.ErrorResultSchema.GetVariableName(TargetLanguage.CSharp, "exception")));
            this.Write(".WithApplicationError((");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.ErrorCodeSchema.GetTypeName(TargetLanguage.CSharp)));
            this.Write(")");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.ErrorCodeName.GetVariableName(TargetLanguage.CSharp)));
            this.Write(", ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.GetInfoName(actionSpec.ErrorInfoName)));
            this.Write(");\r\n                    }\r\n\r\n");
 } 
            this.Write("                    throw ");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.ErrorResultSchema.GetVariableName(TargetLanguage.CSharp, "exception")));
            this.Write(";\r\n                }\r\n                else\r\n                {\r\n                  " +
                    "  return new ExtendedResponse<");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.SchemaType(actionSpec.NormalResultSchema, actionSpec.SerializerEmptyType)));
            this.Write(">\r\n                    {\r\n");
 if (actionSpec.NormalResultName != null) { 
            this.Write("                        Response = extended.Response.");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.NormalResultName.GetFieldName(TargetLanguage.CSharp)));
            this.Write("!,\r\n");
 } else { 
            this.Write("                        Response = new ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.SchemaType(actionSpec.NormalResultSchema, actionSpec.SerializerEmptyType)));
            this.Write("\r\n                        {\r\n");
 foreach (CodeName normalResultName in actionSpec.NormalResultNames) { 
            this.Write("                            ");
            this.Write(this.ToStringHelper.ToStringWithCulture(normalResultName.GetFieldName(TargetLanguage.CSharp)));
            this.Write(" = extended.Response.");
            this.Write(this.ToStringHelper.ToStringWithCulture(normalResultName.GetFieldName(TargetLanguage.CSharp)));
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.NormalRequiredNames.Contains(normalResultName) ? ".Value()" : ""));
            this.Write(",\r\n");
 } 
            this.Write("                        },\r\n");
 } 
            this.Write("                        ResponseMetadata = extended.ResponseMetadata,\r\n          " +
                    "          };\r\n                }\r\n            }\r\n");
 } 
 } 
 foreach (var propSpec in this.propSpecs) { 
 if (propSpec.ReadErrorName != null) { 
            this.Write("\r\n            private async Task<ExtendedResponse<");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.SchemaType(propSpec.PropSchema, propSpec.ReadSerializerEmptyType)));
            this.Write(">> ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetMethodName(TargetLanguage.CSharp, "int", prefix: "read")));
            this.Write("(");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.ReadSerializerEmptyType.GetTypeName(TargetLanguage.CSharp)));
            this.Write(" request, CommandRequestMetadata? requestMetadata, Dictionary<string, string>? pr" +
                    "efixedAdditionalTopicTokenMap, TimeSpan? commandTimeout, CancellationToken cance" +
                    "llationToken)\r\n            {\r\n                ExtendedResponse<");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.SchemaType(propSpec.ReadRespSchema, propSpec.ReadSerializerEmptyType)));
            this.Write("> extended = await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "read", "requester")));
            this.Write(".InvokeCommandAsync(request, requestMetadata, prefixedAdditionalTopicTokenMap, co" +
                    "mmandTimeout, cancellationToken);\r\n\r\n                if (extended.Response.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.ReadErrorName.GetFieldName(TargetLanguage.CSharp)));
            this.Write(" != null)\r\n                {\r\n                    ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.ReadErrorSchema.GetTypeName(TargetLanguage.CSharp, "exception")));
            this.Write(" ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.ReadErrorSchema.GetVariableName(TargetLanguage.CSharp, "exception")));
            this.Write(" = new ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.ReadErrorSchema.GetTypeName(TargetLanguage.CSharp, "exception")));
            this.Write("(extended.Response.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.ReadErrorName.GetFieldName(TargetLanguage.CSharp)));
            this.Write(");\r\n                    throw ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.ReadErrorSchema.GetVariableName(TargetLanguage.CSharp, "exception")));
            this.Write(";\r\n                }\r\n                else if (extended.Response.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.PropValueName.GetFieldName(TargetLanguage.CSharp)));
            this.Write(@" == null)
                {
                    throw new AkriMqttException(""Property read response has neither normal nor error payload content"")
                    {
                        Kind = AkriMqttErrorKind.PayloadInvalid,
                        IsShallow = false,
                        IsRemote = false,
                    };
                }
                else
                {
                    return new ExtendedResponse<");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.SchemaType(propSpec.PropSchema, propSpec.ReadSerializerEmptyType)));
            this.Write(">\r\n                    {\r\n");
 if (propSpec.IsAggregate) { 
            this.Write("                        Response = extended.Response.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.PropValueName.GetFieldName(TargetLanguage.CSharp)));
            this.Write(",\r\n");
 } else { 
            this.Write("                        Response = new ");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.SchemaType(propSpec.PropSchema, propSpec.ReadSerializerEmptyType)));
            this.Write(" { ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.PropValueName.GetFieldName(TargetLanguage.CSharp)));
            this.Write(" = extended.Response.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.PropValueName.GetFieldName(TargetLanguage.CSharp)));
            this.Write(".Value() },\r\n");
 } 
            this.Write("                        ResponseMetadata = extended.ResponseMetadata,\r\n          " +
                    "          };\r\n                }\r\n            }\r\n");
 } 
 if (propSpec.WriteReqSchema != null && propSpec.WriteErrorName != null) { 
            this.Write("\r\n            private async Task<ExtendedResponse<");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.WriteSerializerEmptyType.GetTypeName(TargetLanguage.CSharp)));
            this.Write(">> ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetMethodName(TargetLanguage.CSharp, "int", prefix: "write")));
            this.Write("(");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.WriteReqSchema.GetTypeName(TargetLanguage.CSharp)));
            this.Write(" request, CommandRequestMetadata? requestMetadata, Dictionary<string, string>? pr" +
                    "efixedAdditionalTopicTokenMap, TimeSpan? commandTimeout, CancellationToken cance" +
                    "llationToken)\r\n            {\r\n                ExtendedResponse<");
            this.Write(this.ToStringHelper.ToStringWithCulture(this.SchemaType(propSpec.WriteRespSchema, propSpec.WriteSerializerEmptyType)));
            this.Write("> extended = await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "write", "requester")));
            this.Write(".InvokeCommandAsync(request, requestMetadata, prefixedAdditionalTopicTokenMap, co" +
                    "mmandTimeout, cancellationToken);\r\n\r\n                if (extended.Response.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.WriteErrorName.GetFieldName(TargetLanguage.CSharp)));
            this.Write(" != null)\r\n                {\r\n                    ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.WriteErrorSchema.GetTypeName(TargetLanguage.CSharp, "exception")));
            this.Write(" ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.WriteErrorSchema.GetVariableName(TargetLanguage.CSharp, "exception")));
            this.Write(" = new ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.WriteErrorSchema.GetTypeName(TargetLanguage.CSharp, "exception")));
            this.Write("(extended.Response.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.WriteErrorName.GetFieldName(TargetLanguage.CSharp)));
            this.Write(");\r\n                    throw ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.WriteErrorSchema.GetVariableName(TargetLanguage.CSharp, "exception")));
            this.Write(";\r\n                }\r\n                else\r\n                {\r\n                  " +
                    "  return new ExtendedResponse<");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.WriteSerializerEmptyType.GetTypeName(TargetLanguage.CSharp)));
            this.Write(">\r\n                    {\r\n                        Response = ");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.WriteSerializerEmptyType.GetAllocator(TargetLanguage.CSharp)));
            this.Write(",\r\n                        ResponseMetadata = extended.ResponseMetadata,\r\n       " +
                    "             };\r\n                }\r\n            }\r\n");
 } 
 } 
            this.Write("\r\n            public async ValueTask DisposeAsync()\r\n            {\r\n");
 foreach (var actionSpec in this.actionSpecs) { 
            this.Write("                await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Invoker.GetVariableName(TargetLanguage.CSharp)));
            this.Write(".DisposeAsync().ConfigureAwait(false);\r\n");
 } 
 foreach (var propSpec in this.propSpecs) { 
            this.Write("                await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "read", "requester")));
            this.Write(".DisposeAsync().ConfigureAwait(false);\r\n");
 if (propSpec.WriteReqSchema != null) { 
            this.Write("                await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "write", "requester")));
            this.Write(".DisposeAsync().ConfigureAwait(false); \r\n");
 } 
 } 
 foreach (var telemEnvoyInfo in this.eventSpec) { 
            this.Write("                await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(telemEnvoyInfo.Receiver.GetVariableName(TargetLanguage.CSharp)));
            this.Write(".DisposeAsync().ConfigureAwait(false);\r\n");
 } 
            this.Write("            }\r\n\r\n            public async ValueTask DisposeAsync(bool disposing, " +
                    "CancellationToken cancellationToken = default)\r\n            {\r\n");
 foreach (var actionSpec in this.actionSpecs) { 
            this.Write("                await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(actionSpec.Invoker.GetVariableName(TargetLanguage.CSharp)));
            this.Write(".DisposeAsync(disposing, cancellationToken).ConfigureAwait(false);\r\n");
 } 
 foreach (var propSpec in this.propSpecs) { 
            this.Write("                await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "read", "requester")));
            this.Write(".DisposeAsync(disposing, cancellationToken).ConfigureAwait(false);\r\n");
 if (propSpec.WriteReqSchema != null) { 
            this.Write("                await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(propSpec.Name.GetVariableName(TargetLanguage.CSharp, "write", "requester")));
            this.Write(".DisposeAsync(disposing, cancellationToken).ConfigureAwait(false); \r\n");
 } 
 } 
 foreach (var telemEnvoyInfo in this.eventSpec) { 
            this.Write("                await this.");
            this.Write(this.ToStringHelper.ToStringWithCulture(telemEnvoyInfo.Receiver.GetVariableName(TargetLanguage.CSharp)));
            this.Write(".DisposeAsync(disposing, cancellationToken).ConfigureAwait(false);\r\n");
 } 
            this.Write("            }\r\n        }\r\n");
 } 
            this.Write("    }\r\n}\r\n");
            return this.GenerationEnvironment.ToString();
        }

    private string IntLValue(ActionSpec actionSpec) => (actionSpec.ResponseSchema != null ? $"ExtendedResponse<{this.SchemaType(actionSpec.ErrorResultName != null ? actionSpec.NormalResultSchema : actionSpec.ResponseSchema, actionSpec.SerializerEmptyType)}> extended = " : $"CommandResponseMetadata? responseMetadata = ");

    private string IntRValue(ActionSpec actionSpec) => (actionSpec.ResponseSchema != null ? "Response = extended.Response, ResponseMetadata = extended.ResponseMetadata " : "ResponseMetadata = responseMetadata ");

    private string ExtRespType(ActionSpec actionSpec) => this.CondWrap(actionSpec.ResponseSchema != null ? $"ExtendedResponse<{this.SchemaType(actionSpec.ErrorResultName != null ? actionSpec.NormalResultSchema : actionSpec.ResponseSchema, actionSpec.SerializerEmptyType)}>" : "CommandResponseMetadata?");

    private string EmptyResp(ActionSpec actionSpec) => this.CondFrom(actionSpec.ResponseSchema != null ? $"new ExtendedResponse<{this.SchemaType(actionSpec.ErrorResultName != null ? actionSpec.NormalResultSchema : actionSpec.ResponseSchema, actionSpec.SerializerEmptyType)}> {{ Response = new {this.SchemaType(actionSpec.ErrorResultName != null ? actionSpec.NormalResultSchema : actionSpec.ResponseSchema, actionSpec.SerializerEmptyType)}() }}" : "(CommandResponseMetadata?)new CommandResponseMetadata()");

    private string CondWrap(string type) => $"Task<{type}>";

    private string CondFrom(string res) => $"Task.FromResult({res})";

    private string ReqParam(ActionSpec actionSpec) => actionSpec.RequestSchema != null ? $"{this.SchemaType(actionSpec.RequestSchema, actionSpec.SerializerEmptyType)} request, " : "";

    private string ReqArgs(ActionSpec actionSpec, string reqVar) => actionSpec.RequestSchema != null ? $"{reqVar}.Request!, {reqVar}.RequestMetadata!" : $"{reqVar}.RequestMetadata!";

    private string CallAsyncType(ActionSpec actionSpec) => $"RpcCallAsync<{this.SchemaType(actionSpec.ErrorResultName != null ? actionSpec.NormalResultSchema : actionSpec.ResponseSchema, actionSpec.SerializerEmptyType)}>";

    private string CallAsyncType(PropertySpec propSpec) => $"RpcCallAsync<{this.SchemaType(propSpec.PropSchema, propSpec.ReadSerializerEmptyType)}>";

    private string IntMethod(ActionSpec actionSpec) => actionSpec.ErrorResultName != null ? actionSpec.Name.GetMethodName(TargetLanguage.CSharp, "int") : $"{actionSpec.Invoker.GetVariableName(TargetLanguage.CSharp)}.InvokeCommandAsync";

    private string IntReadMethod(PropertySpec propSpec) => propSpec.ReadErrorName != null ? propSpec.Name.GetMethodName(TargetLanguage.CSharp, "int", prefix: "read") : $"{propSpec.Name.GetVariableName(TargetLanguage.CSharp, "read", "requester")}.InvokeCommandAsync";

    private string IntWriteMethod(PropertySpec propSpec) => propSpec.WriteErrorName != null ? propSpec.Name.GetMethodName(TargetLanguage.CSharp, "int", prefix: "write") : $"{propSpec.Name.GetVariableName(TargetLanguage.CSharp, "write", "requester")}.InvokeCommandAsync";

    private string SchemaType(ITypeName schema, EmptyTypeName emptyType) => schema?.GetTypeName(TargetLanguage.CSharp) ?? emptyType.GetTypeName(TargetLanguage.CSharp);

    private string ExecParam(ActionSpec actionSpec) => actionSpec.DoesTargetExecutor ? "string executorId, " : "";

    private string ReadMaintParam(PropertySpec propSpec) => propSpec.DoesReadTargetMaintainer ? "string maintainerId, " : "";

    private string WriteMaintParam(PropertySpec propSpec) => propSpec.DoesWriteTargetMaintainer ? "string maintainerId, " : "";

    private bool IsLast(ActionSpec actionSpec) => actionSpec.Name.AsGiven == this.actionSpecs.Last().Name.AsGiven && !this.propSpecs.Any();

    private bool IsLast(PropertySpec propSpec) => propSpec.Name == null || propSpec.Name.AsGiven == this.propSpecs.Last().Name.AsGiven;

    private bool IsLast(EventSpec telemEnvoyInfo) => telemEnvoyInfo.Name.AsGiven == this.eventSpec.Last().Name.AsGiven;

    private string TelemMethodName(EventSpec telemEnvoyInfo, string prefix, string suffix = null) => ((telemEnvoyInfo.Schema is RawTypeName || telemEnvoyInfo.Schema is CustomTypeName) ? telemEnvoyInfo.Name : new CodeName()).GetMethodName(TargetLanguage.CSharp, "telemetry", suffix, prefix: prefix);

    private string GetInfoName(CodeName infoName) => infoName?.GetVariableName(TargetLanguage.CSharp) ?? "errorPayload";

    private string GetInfoSchema(CodeName infoSchema) => infoSchema?.GetTypeName(TargetLanguage.CSharp) ?? "string";

    }
    #region Base class
    /// <summary>
    /// Base class for this transformation
    /// </summary>
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "18.0.0.0")]
    public class DotNetServiceBase
    {
        #region Fields
        private global::System.Text.StringBuilder generationEnvironmentField;
        private global::System.CodeDom.Compiler.CompilerErrorCollection errorsField;
        private global::System.Collections.Generic.List<int> indentLengthsField;
        private string currentIndentField = "";
        private bool endsWithNewline;
        private global::System.Collections.Generic.IDictionary<string, object> sessionField;
        #endregion
        #region Properties
        /// <summary>
        /// The string builder that generation-time code is using to assemble generated output
        /// </summary>
        public System.Text.StringBuilder GenerationEnvironment
        {
            get
            {
                if ((this.generationEnvironmentField == null))
                {
                    this.generationEnvironmentField = new global::System.Text.StringBuilder();
                }
                return this.generationEnvironmentField;
            }
            set
            {
                this.generationEnvironmentField = value;
            }
        }
        /// <summary>
        /// The error collection for the generation process
        /// </summary>
        public System.CodeDom.Compiler.CompilerErrorCollection Errors
        {
            get
            {
                if ((this.errorsField == null))
                {
                    this.errorsField = new global::System.CodeDom.Compiler.CompilerErrorCollection();
                }
                return this.errorsField;
            }
        }
        /// <summary>
        /// A list of the lengths of each indent that was added with PushIndent
        /// </summary>
        private System.Collections.Generic.List<int> indentLengths
        {
            get
            {
                if ((this.indentLengthsField == null))
                {
                    this.indentLengthsField = new global::System.Collections.Generic.List<int>();
                }
                return this.indentLengthsField;
            }
        }
        /// <summary>
        /// Gets the current indent we use when adding lines to the output
        /// </summary>
        public string CurrentIndent
        {
            get
            {
                return this.currentIndentField;
            }
        }
        /// <summary>
        /// Current transformation session
        /// </summary>
        public virtual global::System.Collections.Generic.IDictionary<string, object> Session
        {
            get
            {
                return this.sessionField;
            }
            set
            {
                this.sessionField = value;
            }
        }
        #endregion
        #region Transform-time helpers
        /// <summary>
        /// Write text directly into the generated output
        /// </summary>
        public void Write(string textToAppend)
        {
            if (string.IsNullOrEmpty(textToAppend))
            {
                return;
            }
            // If we're starting off, or if the previous text ended with a newline,
            // we have to append the current indent first.
            if (((this.GenerationEnvironment.Length == 0) 
                        || this.endsWithNewline))
            {
                this.GenerationEnvironment.Append(this.currentIndentField);
                this.endsWithNewline = false;
            }
            // Check if the current text ends with a newline
            if (textToAppend.EndsWith(global::System.Environment.NewLine, global::System.StringComparison.CurrentCulture))
            {
                this.endsWithNewline = true;
            }
            // This is an optimization. If the current indent is "", then we don't have to do any
            // of the more complex stuff further down.
            if ((this.currentIndentField.Length == 0))
            {
                this.GenerationEnvironment.Append(textToAppend);
                return;
            }
            // Everywhere there is a newline in the text, add an indent after it
            textToAppend = textToAppend.Replace(global::System.Environment.NewLine, (global::System.Environment.NewLine + this.currentIndentField));
            // If the text ends with a newline, then we should strip off the indent added at the very end
            // because the appropriate indent will be added when the next time Write() is called
            if (this.endsWithNewline)
            {
                this.GenerationEnvironment.Append(textToAppend, 0, (textToAppend.Length - this.currentIndentField.Length));
            }
            else
            {
                this.GenerationEnvironment.Append(textToAppend);
            }
        }
        /// <summary>
        /// Write text directly into the generated output
        /// </summary>
        public void WriteLine(string textToAppend)
        {
            this.Write(textToAppend);
            this.GenerationEnvironment.AppendLine();
            this.endsWithNewline = true;
        }
        /// <summary>
        /// Write formatted text directly into the generated output
        /// </summary>
        public void Write(string format, params object[] args)
        {
            this.Write(string.Format(global::System.Globalization.CultureInfo.CurrentCulture, format, args));
        }
        /// <summary>
        /// Write formatted text directly into the generated output
        /// </summary>
        public void WriteLine(string format, params object[] args)
        {
            this.WriteLine(string.Format(global::System.Globalization.CultureInfo.CurrentCulture, format, args));
        }
        /// <summary>
        /// Raise an error
        /// </summary>
        public void Error(string message)
        {
            System.CodeDom.Compiler.CompilerError error = new global::System.CodeDom.Compiler.CompilerError();
            error.ErrorText = message;
            this.Errors.Add(error);
        }
        /// <summary>
        /// Raise a warning
        /// </summary>
        public void Warning(string message)
        {
            System.CodeDom.Compiler.CompilerError error = new global::System.CodeDom.Compiler.CompilerError();
            error.ErrorText = message;
            error.IsWarning = true;
            this.Errors.Add(error);
        }
        /// <summary>
        /// Increase the indent
        /// </summary>
        public void PushIndent(string indent)
        {
            if ((indent == null))
            {
                throw new global::System.ArgumentNullException("indent");
            }
            this.currentIndentField = (this.currentIndentField + indent);
            this.indentLengths.Add(indent.Length);
        }
        /// <summary>
        /// Remove the last indent that was added with PushIndent
        /// </summary>
        public string PopIndent()
        {
            string returnValue = "";
            if ((this.indentLengths.Count > 0))
            {
                int indentLength = this.indentLengths[(this.indentLengths.Count - 1)];
                this.indentLengths.RemoveAt((this.indentLengths.Count - 1));
                if ((indentLength > 0))
                {
                    returnValue = this.currentIndentField.Substring((this.currentIndentField.Length - indentLength));
                    this.currentIndentField = this.currentIndentField.Remove((this.currentIndentField.Length - indentLength));
                }
            }
            return returnValue;
        }
        /// <summary>
        /// Remove any indentation
        /// </summary>
        public void ClearIndent()
        {
            this.indentLengths.Clear();
            this.currentIndentField = "";
        }
        #endregion
        #region ToString Helpers
        /// <summary>
        /// Utility class to produce culture-oriented representation of an object as a string.
        /// </summary>
        public class ToStringInstanceHelper
        {
            private System.IFormatProvider formatProviderField  = global::System.Globalization.CultureInfo.InvariantCulture;
            /// <summary>
            /// Gets or sets format provider to be used by ToStringWithCulture method.
            /// </summary>
            public System.IFormatProvider FormatProvider
            {
                get
                {
                    return this.formatProviderField ;
                }
                set
                {
                    if ((value != null))
                    {
                        this.formatProviderField  = value;
                    }
                }
            }
            /// <summary>
            /// This is called from the compile/run appdomain to convert objects within an expression block to a string
            /// </summary>
            public string ToStringWithCulture(object objectToConvert)
            {
                if ((objectToConvert == null))
                {
                    throw new global::System.ArgumentNullException("objectToConvert");
                }
                System.Type t = objectToConvert.GetType();
                System.Reflection.MethodInfo method = t.GetMethod("ToString", new System.Type[] {
                            typeof(System.IFormatProvider)});
                if ((method == null))
                {
                    return objectToConvert.ToString();
                }
                else
                {
                    return ((string)(method.Invoke(objectToConvert, new object[] {
                                this.formatProviderField })));
                }
            }
        }
        private ToStringInstanceHelper toStringHelperField = new ToStringInstanceHelper();
        /// <summary>
        /// Helper to produce culture-oriented representation of an object as a string
        /// </summary>
        public ToStringInstanceHelper ToStringHelper
        {
            get
            {
                return this.toStringHelperField;
            }
        }
        #endregion
    }
    #endregion
}
