コード例 #1
0
 private async Task RunAsync(CancellationToken cancellationToken)
 {
     while (!cancellationToken.IsCancellationRequested)
     {
         RbTraceLog.WriteLog("Working");
         await Task.Delay(1000);
     }
 }
        Task IEventProcessor.OpenAsync(PartitionContext context)
        {
            RbTraceLog.Initialize(rbTraceStorageConnString, rbTraceTableName, "CloudRoboticsFX");
            string msg = string.Format("RoboticsEventProcessor initialize.  Partition:{0}, Offset:{1}",
                                       context.Lease.PartitionId, context.Lease.Offset);

            RbTraceLog.WriteLog(msg);

            return(Task.FromResult <object>(null));
        }
コード例 #3
0
        public override void OnStop()
        {
            RbTraceLog.WriteLog("CloudRoboticsWoker is stopping");

            this.runCompleteEvent.Set();
            eventProcessorHost.UnregisterEventProcessorAsync().Wait();

            base.OnStop();

            RbTraceLog.WriteLog("CloudRoboticsWoker has stopped");
        }
コード例 #4
0
        public override void Run()
        {
            RbTraceLog.WriteLog("CloudRoboticsWoker is running");

            // Delete archived DLL directory
            string archivedDirectory = Environment.CurrentDirectory + @"\" + archivedDirectoryName;

            if (Directory.Exists(archivedDirectory))
            {
                Directory.Delete(archivedDirectory, true);
            }

            // Event Processor Host
            eventProcessorHost.RegisterEventProcessorAsync <RoboticsEventProcessor>();

            //Wait for shutdown to be called, else the role will recycle
            this.runCompleteEvent.WaitOne();
        }
        JArray ProcessControlMessage(RbHeader rbh)
        {
            JArray ja_messages = new JArray();

            try
            {
                RbAppMasterCache rbappmc = GetAppMasterInfo(rbh);
                RbMessage        message = new RbMessage();
                message.RbHeader = rbh;
                message.RbBody   = JsonConvert.DeserializeObject <JObject>(rbappmc.AppInfoDevice);
                string  json_message = JsonConvert.SerializeObject(message);
                JObject jo           = (JObject)JsonConvert.DeserializeObject(json_message);
                ja_messages.Add(jo);
            }
            catch (Exception ex)
            {
                RbTraceLog.WriteError("E004", ex.ToString());
                ae = new ApplicationException("Error ** <<CONTROL Message Processing>> Exception occured during JSON processing on RBFX.AppMaster[AppInfoDevice]");
                throw ae;
            }
            return(ja_messages);
        }
コード例 #6
0
        private async Task ProcessMessage(EventData eventData, long partitionKey, RbTraceLog rbTraceLog)
        {
            // Receive a message and system properties
            string   iothub_deviceId        = (string)eventData.SystemProperties["iothub-connection-device-id"];
            DateTime iothub_enqueuedTimeUtc = (DateTime)eventData.SystemProperties.EnqueuedTimeUtc;
            string   text_message           = Encoding.UTF8.GetString(eventData.Body.Array);

            // RbTrace (Table Storage)
            if (rbTraceLevel == RbTraceType.Detail)
            {
                rbTraceLog.WriteLog($"Received a message. Partition({partitionKey}), DeviceId({iothub_deviceId}), Message:{text_message}");
            }

            // Loop of retry for reconfiguration on SQL Database
            int loopCounter = 0;

            while (true)
            {
                JObject jo_message = null;

                // Routing switch
                bool devRouting = false;
                bool appRouting = false;

                try
                {
                    // Check RbHeader
                    if (text_message.IndexOf(RbFormatType.RbHeader) < 0)
                    {
                        rbTraceLog.WriteLog(RbExceptionMessage.RbHeaderNotFound
                                            + $" Partition({partitionKey}), DeviceId({iothub_deviceId}), Message:{text_message}");
                        return;
                    }

                    // Check RbHeader simplly
                    jo_message = JsonConvert.DeserializeObject <JObject>(text_message);
                    var jo_rbh = (JObject)jo_message[RbFormatType.RbHeader];

                    var v_rbhRoutingType = jo_rbh[RbHeaderElement.RoutingType];
                    if (v_rbhRoutingType == null)
                    {
                        rbTraceLog.WriteError("W001", "** Message skipped because RoutingType is null **", jo_message);
                        return;
                    }
                    string s_rbhRoutingType = (string)v_rbhRoutingType;
                    if (s_rbhRoutingType == RbRoutingType.LOG || s_rbhRoutingType == string.Empty)
                    {
                        // RoutingType == LOG -> only using IoT Hub with Stream Analytics
                        return;
                    }

                    // Check RbHeader in detail
                    RbHeaderBuilder hdBuilder = new RbHeaderBuilder(jo_message, iothub_deviceId);
                    RbHeader        rbh       = null;
                    try
                    {
                        rbh = hdBuilder.ValidateJsonSchema();
                    }
                    catch (Exception ex)
                    {
                        rbTraceLog.WriteError("W002", "** Message skipped because of bad RbHeader **", ex);
                        return;
                    }

                    // Check StorageQueueSendEnabled property in RbHeader
                    prevStorageQueueSendEnabled = storageQueueSendEnabled;
                    string messageStorageQueueSendEnabled = null;
                    if (storageQueueSendEnabled != "true")
                    {
                        try
                        {
                            messageStorageQueueSendEnabled = (string)jo_rbh[typeStorageQueueSendEnabled];
                        }
                        catch
                        {
                            messageStorageQueueSendEnabled = null;
                        }
                        if (messageStorageQueueSendEnabled == "true")
                        {
                            storageQueueSendEnabled = messageStorageQueueSendEnabled;
                        }
                    }

                    // Check RoutingType (CALL, D2D, CONTROL)
                    if (rbh.RoutingType == RbRoutingType.CALL || rbh.RoutingType == RbRoutingType.CALL_ASYNC)
                    {
                        appRouting = true;
                    }
                    else if (rbh.RoutingType == RbRoutingType.D2D)
                    {
                        devRouting = true;
                        if (rbh.AppProcessingId != string.Empty)
                        {
                            appRouting = true;
                        }
                    }
                    else if (rbh.RoutingType == RbRoutingType.CONTROL)
                    {
                        devRouting = false;
                        appRouting = false;
                    }
                    else
                    {
                        rbTraceLog.WriteError("W003", "** Message skipped because of bad RoutingType **", jo_message);
                        return;
                    }

                    // Device Router builds RbHeader
                    DeviceRouter dr = null;
                    if (devRouting)
                    {
                        dr  = new DeviceRouter(rbh, sqlConnectionString);
                        rbh = dr.GetDeviceRouting();
                        string new_header = JsonConvert.SerializeObject(rbh);
                        jo_message[RbFormatType.RbHeader] = JsonConvert.DeserializeObject <JObject>(new_header);
                    }
                    else
                    {
                        rbh.TargetDeviceId = rbh.SourceDeviceId;
                        rbh.TargetType     = RbTargetType.Device;
                    }

                    // Application Routing
                    JArray ja_messages = null;
                    if (appRouting)
                    {
                        // Application Call Logic
                        JObject jo_temp;
                        string  rbBodyString;
                        try
                        {
                            jo_temp      = (JObject)jo_message[RbFormatType.RbBody];
                            rbBodyString = JsonConvert.SerializeObject(jo_temp);
                        }
                        catch (Exception ex)
                        {
                            rbTraceLog.WriteError("E001", $"** RbBody is not regular JSON format ** {ex.ToString()}", jo_message);
                            return;
                        }

                        try
                        {
                            if (rbh.RoutingType == RbRoutingType.CALL_ASYNC)
                            {
                                await CallAppsWithQueue(rbh, rbBodyString, partitionKey.ToString());
                            }
                            else
                            {
                                ja_messages = await CallAppsWithHttp(rbh, rbBodyString, partitionKey.ToString());
                            }
                        }
                        catch (Exception ex)
                        {
                            rbTraceLog.WriteError("E002", $"** Error occured in CallApps ** {ex.ToString()}", jo_message);
                            return;
                        }
                    }
                    else
                    {
                        ja_messages = new JArray();
                        ja_messages.Add(jo_message);
                    }

                    // Send C2D Message
                    if (rbh.RoutingType == RbRoutingType.CALL ||
                        rbh.RoutingType == RbRoutingType.D2D ||
                        rbh.RoutingType == RbRoutingType.CONTROL)
                    {
                        if (storageQueueSendEnabled == "true")
                        {
                            // Send C2D message to Queue storage
                            RbC2dMessageToQueue c2dsender = null;
                            c2dsender = new RbC2dMessageToQueue(ja_messages, storageQueueConnString, sqlConnectionString);
                            await c2dsender.SendToDeviceAsync();
                        }
                        else
                        {
                            // Send C2D message to IoT Hub
                            RbC2dMessageSender c2dsender = null;
                            c2dsender = new RbC2dMessageSender(ja_messages, iotHubConnectionString, sqlConnectionString);
                            await c2dsender.SendToDeviceAsync();
                        }
                        // StorageQueueSendEnabled property in RbHeader
                        storageQueueSendEnabled = prevStorageQueueSendEnabled;
                    }

                    // Get out of retry loop because of normal completion
                    break;
                }
                catch (Exception ex)
                {
                    rbTraceLog.WriteError("E003", $"** Critical error occured ** {ex.ToString()}", jo_message);

                    bool continueLoop = false;

                    if (ex != null && ex is SqlException)
                    {
                        foreach (SqlError error in (ex as SqlException).Errors)
                        {
                            if (sqlErrorListForRetry.Contains(error.Number))
                            {
                                continueLoop = true;
                                break;  // Exit foreach loop
                            }
                        }

                        if (continueLoop)
                        {
                            ++loopCounter;
                            rbTraceLog.WriteLog($"Transaction retry has started. Count({loopCounter})");

                            if (loopCounter > maxLoopCounter)
                            {
                                break;  // Get out of retry loop because counter reached max number
                            }
                            else
                            {
                                Thread.Sleep(sleepInterval);
                            }
                        }
                        else
                        {
                            break;  // Get out of retry loop because of another sql error
                        }
                    }
                    else
                    {
                        throw;
                    }
                }
            }
        }
コード例 #7
0
        /// <summary>
        /// This is a main entry point of Service replica.
        /// This method can be executable when the replica is primary.
        /// </summary>
        /// <param name="cancellationToken">When Service Fabric needs to shutdown this Service replica, it is cancelled.</param>
        protected override async Task RunAsync(CancellationToken cancellationToken)
        {
            // Environment variables
            InitializeSetting();

            // Initialize RbTraceLog
            rbTraceLog = new RbTraceLog(rbTraceStorageConnString, rbTraceStorageTableName,
                                        "CloudRoboticsFx3", this.Context.TraceId.ToString());

            rbTraceLog.CreateLogTableIfNotExists();

            // These Reliable Dictionaries are used to keep track of our position in IoT Hub.
            // If this service fails over, this will allow it to pick up where it left off in the event stream.
            IReliableDictionary <string, string> offsetDictionary =
                await this.StateManager.GetOrAddAsync <IReliableDictionary <string, string> >(OffsetDictionaryName);

            IReliableDictionary <string, long> epochDictionary =
                await this.StateManager.GetOrAddAsync <IReliableDictionary <string, long> >(EpochDictionaryName);

            // Each partition of this service corresponds to a partition in IoT Hub.
            // IoT Hub partitions are numbered 0..n-1, up to n = 32.
            // This service needs to use an identical partitioning scheme.
            // The low key of every partition corresponds to an IoT Hub partition.
            Int64RangePartitionInformation partitionInfo = (Int64RangePartitionInformation)this.Partition.PartitionInfo;
            long servicePartitionKey = partitionInfo.LowKey;

            EventHubClient    client            = null;
            PartitionReceiver partitionReceiver = null;
            int retryCount = 0;

            try
            {
                // ETW Trace
                ServiceEventSource.Current.ServiceMessage(this.Context, $"CloudRoboFxSvc has started. Partition({servicePartitionKey})");
                // RbTrace (Table Storage)
                rbTraceLog.WriteLog($"CloudRoboFxSvc has started. Partition({servicePartitionKey})");

                // Get a partitionReceiver with EventHubClient.
                // The partitionReceiver is used to get events from IoT Hub.
                client            = EventHubClient.CreateFromConnectionString(compatibleEventHubConnString);
                partitionReceiver = await this.ConnectToIoTHubAsync(client, iotHubConsumerGroup,
                                                                    servicePartitionKey, epochDictionary, offsetDictionary);

                string previousOffset = string.Empty;

                // Loop of Processing EventData
                while (true)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    try
                    {
                        int maxReceivedBatchSize = 50;
                        int maxWaitTimeMilliSec  = 5000;
                        IEnumerable <EventData> receivedEvents = await partitionReceiver.ReceiveAsync(maxReceivedBatchSize,
                                                                                                      TimeSpan.FromMilliseconds(maxWaitTimeMilliSec));

                        if (receivedEvents == null)
                        {
                            continue;
                        }

                        // Process event data
                        foreach (var eventData in receivedEvents)
                        {
                            await ProcessMessage(eventData, servicePartitionKey, rbTraceLog);

                            // Save the current Iot Hub data stream offset.
                            // This will allow the service to pick up from its current location if it fails over.
                            // Duplicate device messages may still be sent to the the tenant service
                            // if this service fails over after the message is sent but before the offset is saved.
                            ServiceEventSource.Current.ServiceMessage(this.Context, "Saving offset {0}",
                                                                      eventData.SystemProperties.Offset);

                            using (ITransaction tx = this.StateManager.CreateTransaction())
                            {
                                await offsetDictionary.SetAsync(tx, "offset", eventData.SystemProperties.Offset);

                                await tx.CommitAsync();
                            }
                        }
                    }
                    catch (TimeoutException te)
                    {
                        // transient error. Retry.
                        ServiceEventSource.Current.ServiceMessage(this.Context, $"TimeoutException in RunAsync: {te.ToString()}");
                        rbTraceLog.WriteError("E004", $"** TimeoutException in RunAsync ** {te.ToString()}");
                    }
                    catch (FabricTransientException fte)
                    {
                        // transient error. Retry.
                        ServiceEventSource.Current.ServiceMessage(this.Context, $"FabricTransientException in RunAsync: {fte.ToString()}");
                        rbTraceLog.WriteError("E005", $"** FabricTransientException in RunAsync ** {fte.ToString()}");
                    }
                    catch (FabricNotPrimaryException)
                    {
                        // not primary any more, time to quit.

                        rbTraceLog.WriteError("E006", $"** FabricNotPrimaryException in RunAsync **");
                        return;
                    }
                    catch (Exception ex)
                    {
                        if (ex is ServerBusyException || ex is TimeoutException)
                        {
                            ++retryCount;
                            if (retryCount > maxEventProcessingRetryCount)
                            {
                                throw;
                            }
                            rbTraceLog.WriteLog("** Retrying to open IoT Hub connection... **");
                            if (partitionReceiver != null)
                            {
                                try { await partitionReceiver.CloseAsync(); } catch { /* None */ }
                                partitionReceiver = null;
                            }
                            await Task.Delay(new TimeSpan(0, 0, 5));

                            partitionReceiver = await this.ConnectToIoTHubAsync(client, iotHubConsumerGroup,
                                                                                servicePartitionKey, epochDictionary, offsetDictionary);

                            previousOffset = string.Empty;

                            continue;
                        }
                        else
                        {
                            ServiceEventSource.Current.ServiceMessage(this.Context, ex.ToString());
                            rbTraceLog.WriteError("E007", $"** Critical error occured ** {ex.ToString()}");

                            throw;
                        }
                    }
                }
            }
            finally
            {
                if (partitionReceiver != null)
                {
                    await partitionReceiver.CloseAsync();
                }
            }
        }
コード例 #8
0
        public override bool OnStart()
        {
            // Max connection Limit
            ServicePointManager.DefaultConnectionLimit = 16;

            // Get properties
            iotHubConnectionString  = CloudConfigurationManager.GetSetting("IoTHub.ConnectionString");
            iotHubClassicConnString = CloudConfigurationManager.GetSetting("IoTHub.ClassicConnectionString");
            int pos = iotHubClassicConnString.IndexOf("sb://");

            if (pos == 0)
            {
                int    pos2            = iotHubConnectionString.IndexOf("SharedAccessKeyName=");
                string sharedAccessKey = iotHubConnectionString.Substring(pos2);
                iotHubClassicConnString = "Endpoint=" + iotHubClassicConnString + ";" + sharedAccessKey;
            }
            iotHubName = CloudConfigurationManager.GetSetting("IoTHub.HubName");
            iotHubConsumerGroupName = CloudConfigurationManager.GetSetting("IoTHub.ConsumerGroupName");
            storageAccountName      = CloudConfigurationManager.GetSetting("IoTHub.StorageAccountName");
            storageAccountKey       = CloudConfigurationManager.GetSetting("IoTHub.StorageAccountKey");
            storageConnectionString = string.Format("DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}",
                                                    storageAccountName, storageAccountKey);
            storageQueueSendEnabled = CloudConfigurationManager.GetSetting("StorageQueue.SendEnabled");

            c2dLogEnabled = CloudConfigurationManager.GetSetting("RbC2dLog.Enable");

            traceStorageAccountName      = CloudConfigurationManager.GetSetting("RbTrace.StorageAccountName");
            traceStorageAccountKey       = CloudConfigurationManager.GetSetting("RbTrace.StorageAccountKey");
            traceStorageConnectionString = string.Format("DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}",
                                                         traceStorageAccountName, traceStorageAccountKey);
            traceTableName = CloudConfigurationManager.GetSetting("RbTrace.StorageTableName");
            traceLevel     = CloudConfigurationManager.GetSetting("RbTrace.TraceLevel");

            // Set properties to Event Processor
            if (c2dLogEnabled != null && c2dLogEnabled.ToLower() == "true")
            {
                RoboticsEventProcessor.rbC2dLogEnabled            = true;
                RoboticsEventProcessor.rbC2dLogEventHubConnString = CloudConfigurationManager.GetSetting("RbC2dLog.EventHubConnString");
                RoboticsEventProcessor.rbC2dLogEventHubName       = CloudConfigurationManager.GetSetting("RbC2dLog.EventHubName");
            }
            else
            {
                RoboticsEventProcessor.rbC2dLogEnabled = false;
            }
            RoboticsEventProcessor.rbTraceStorageConnString = traceStorageConnectionString;
            RoboticsEventProcessor.rbTraceTableName         = traceTableName;
            RoboticsEventProcessor.rbTraceLevel             = traceLevel;
            RoboticsEventProcessor.rbIotHubConnString       = iotHubConnectionString;
            if (storageQueueSendEnabled != null && storageQueueSendEnabled.ToLower() == "true")
            {
                RoboticsEventProcessor.rbStorageQueueSendEnabled = true;
                RoboticsEventProcessor.rbStorageQueueConnString  = storageConnectionString;
            }
            else
            {
                RoboticsEventProcessor.rbStorageQueueSendEnabled = false;
            }
            RoboticsEventProcessor.rbSqlConnectionString = CloudConfigurationManager.GetSetting("SqlConnectionString");
            RoboticsEventProcessor.rbEncPassPhrase       = CloudConfigurationManager.GetSetting("RbEnc.PassPhrase");
            RoboticsEventProcessor.rbCacheExpiredTimeSec = int.Parse(CloudConfigurationManager.GetSetting("RbCache.ExpiredTimeSec"));
            RoboticsEventProcessor.archivedDirectoryName = archivedDirectoryName;

            // Event Processor Host
            string eventProcessorHostName = RoleEnvironment.CurrentRoleInstance.Id;

            eventProcessorHost = new EventProcessorHost(eventProcessorHostName, iotHubName, iotHubConsumerGroupName,
                                                        iotHubClassicConnString, storageConnectionString);

            RbTraceLog.Initialize(traceStorageConnectionString, traceTableName, "CloudRoboticsFX");
            RbTraceLog.CreateLogTableIfNotExists();

            bool result = base.OnStart();

            RbTraceLog.WriteLog("CloudRoboticsWorker has been started");

            return(result);
        }
        async Task IEventProcessor.ProcessEventsAsync(PartitionContext context, IEnumerable <EventData> messages)
        {
            try
            {
                #region *** Handling unexpected exceptions ***

                DateTime startDateTimeUtc = DateTime.UtcNow;
                int      messagecnt       = 0;
                bool     sqlex_on         = false;

                foreach (EventData eventData in messages)
                {
                    try
                    {
                        // Go forward read pointer
                        await context.CheckpointAsync();
                    }
                    catch (Exception ex)
                    {
                        // Handling the exception of Microsoft.ServiceBus.Messaging.LeaseLostException
                        // This exception is usually able to occur.
                        ApplicationException ae = new ApplicationException(checkpointExMessage, ex);
                        throw ae;
                    }

                    ++messagecnt;
                    int      retryCount             = 0;
                    bool     devRouting             = false;
                    bool     appRouting             = false;
                    bool     rbHeaderNotFound       = false;
                    string   sqlConnString          = rbSqlConnectionString;
                    string   iothub_deviceId        = (string)eventData.SystemProperties["iothub-connection-device-id"];
                    DateTime iothub_enqueuedTimeUtc = (DateTime)eventData.SystemProperties["EnqueuedTimeUtc"];
                    string   text_message           = string.Empty;

                    // Retry loop logic for SQLDB reconfiguration exception
                    while (true)
                    {
                        text_message = Encoding.UTF8.GetString(eventData.GetBytes());
                        string text_message_100 = text_message.Substring(0, 100);
                        if (text_message_100.IndexOf(RbFormatType.RbHeader) < 0)
                        {
                            rbHeaderNotFound = true;
                            RbTraceLog.WriteLog(string.Format(RbExceptionMessage.RbHeaderNotFound + "  Partition:{0}, Message:{1}, DeviceId:{2}",
                                                              context.Lease.PartitionId, text_message_100, iothub_deviceId));
                        }

                        if (rbTraceLevel == RbTraceType.Detail)
                        {
                            DateTime dt = iothub_enqueuedTimeUtc;
                            TimeSpan ts = DateTime.UtcNow - dt;
                            RbTraceLog.WriteLog(string.Format("RoboticsEventProcessor Message received.  Delayed time:{0}, Partition:{1}, DeviceId:{2}, Message:{3}",
                                                              ts.ToString(), context.Lease.PartitionId, iothub_deviceId, text_message));
                            if (ts > new TimeSpan(0, 0, 5))
                            {
                                RbTraceLog.WriteLog(string.Format("** Delayed time is over 5 seconds !! **  DelayedTime:{0}, Partition:{1}, DeviceId:{2}, Message:{3}",
                                                                  ts.ToString(), context.Lease.PartitionId, iothub_deviceId, text_message));
                            }
                        }
                        JObject jo_message = null;

                        if (!rbHeaderNotFound)  // Skip invalid data
                        {
                            try
                            {
                                jo_message = JsonConvert.DeserializeObject <JObject>(text_message);

                                // Check RbHeader simplly
                                var jo_rbh = (JObject)jo_message[RbFormatType.RbHeader];
                                if (jo_rbh != null)
                                {
                                    string jo_rbh_RoutingType = (string)jo_rbh[RbHeaderElement.RoutingType];
                                    // Check RoutingType (LOG, null)
                                    if (jo_rbh_RoutingType == null)
                                    {
                                        RbTraceLog.WriteError("W001", "** Message skipped because RoutingType is null **", jo_message);
                                        goto LoopExitLabel;
                                    }
                                    else if (jo_rbh_RoutingType == RbRoutingType.LOG)
                                    {
                                        // RoutingType == LOG -> only using IoT Hub with Stream Analytics
                                        goto LoopExitLabel;
                                    }
                                }

                                // Check RbHeader in detail
                                RbHeaderBuilder hdBuilder = new RbHeaderBuilder(jo_message, iothub_deviceId);
                                RbHeader        rbh       = hdBuilder.ValidateJsonSchema();

                                // Check RoutingType (CALL, D2D, CONTROL)
                                if (rbh.RoutingType == RbRoutingType.CALL)
                                {
                                    appRouting = true;
                                }
                                else if (rbh.RoutingType == RbRoutingType.D2D)
                                {
                                    devRouting = true;
                                    if (rbh.AppProcessingId != string.Empty)
                                    {
                                        appRouting = true;
                                    }
                                }
                                else if (rbh.RoutingType == RbRoutingType.CONTROL)
                                {
                                    devRouting = false;
                                    appRouting = false;
                                }
                                else
                                {
                                    RbTraceLog.WriteError("W002", "** Message skipped because of bad RoutingType **", jo_message);
                                    goto LoopExitLabel;
                                }

                                // Device Router builds RbHeader
                                DeviceRouter dr = null;
                                if (devRouting)
                                {
                                    dr  = new DeviceRouter(rbh, sqlConnString);
                                    rbh = dr.GetDeviceRouting();
                                    string new_header = JsonConvert.SerializeObject(rbh);
                                    jo_message[RbFormatType.RbHeader] = JsonConvert.DeserializeObject <JObject>(new_header);
                                }
                                else
                                {
                                    rbh.TargetDeviceId = rbh.SourceDeviceId;
                                    rbh.TargetType     = RbTargetType.Device;
                                }

                                // Application Routing
                                JArray ja_messages = null;
                                if (appRouting)
                                {
                                    // Application Call Logic
                                    JObject jo_temp      = (JObject)jo_message[RbFormatType.RbBody];
                                    string  rbBodyString = JsonConvert.SerializeObject(jo_temp);
                                    ja_messages = CallApps(rbh, rbBodyString, context.Lease.PartitionId);
                                }
                                else if (rbh.RoutingType != RbRoutingType.CONTROL)
                                {
                                    ja_messages = new JArray();
                                    ja_messages.Add(jo_message);
                                }

                                // RoutingType="CONTROL" and AppProcessingId="ReqAppInfo"
                                if (rbh.RoutingType == RbRoutingType.CONTROL)
                                {
                                    if (rbh.AppProcessingId == null)
                                    {
                                        RbTraceLog.WriteError("W003", "** Message skipped because AppProcessingId is null when CONTROL RoutingType **", jo_message);
                                        goto LoopExitLabel;
                                    }
                                    else if (rbh.AppProcessingId == RbControlType.ReqAppInfo)
                                    {
                                        ja_messages = ProcessControlMessage(rbh);
                                    }
                                    else
                                    {
                                        RbTraceLog.WriteError("W004", "** Message skipped because of bad AppProcessingId when CONTROL RoutingType **", jo_message);
                                        goto LoopExitLabel;
                                    }
                                }

                                // Send C2D Message
                                if (rbh.RoutingType == RbRoutingType.CALL ||
                                    rbh.RoutingType == RbRoutingType.D2D ||
                                    rbh.RoutingType == RbRoutingType.CONTROL)
                                {
                                    if (rbStorageQueueSendEnabled)
                                    {
                                        // Send C2D message to Queue storage
                                        RbC2dMessageToQueue c2dsender = null;
                                        c2dsender = new RbC2dMessageToQueue(ja_messages, rbStorageQueueConnString, sqlConnString);
                                        c2dsender.SendToDevice();
                                    }
                                    else
                                    {
                                        // Send C2D message to IoT Hub
                                        RbC2dMessageSender c2dsender = null;
                                        c2dsender = new RbC2dMessageSender(ja_messages, rbIotHubConnString, sqlConnString);
                                        c2dsender.SendToDevice();
                                    }
                                }

                                // C2D Message Logging to Event Hub
                                if (rbC2dLogEnabled)
                                {
                                    RbEventHubs rbEventHubs = new RbEventHubs(rbC2dLogEventHubConnString, rbC2dLogEventHubName);
                                    foreach (JObject jo in ja_messages)
                                    {
                                        string str_message = JsonConvert.SerializeObject(jo);
                                        rbEventHubs.SendMessage(str_message, iothub_deviceId);
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                sqlex_on = false;

                                if (ex != null && ex is SqlException)  // "is" matches extended type as well
                                {
                                    foreach (SqlError error in (ex as SqlException).Errors)
                                    {
                                        if (sqlErrorListForRetry.Contains(error.Number))
                                        {
                                            sqlex_on = true;
                                            break;  // Exit foreach loop
                                        }
                                    }

                                    if (sqlex_on)
                                    {
                                        ++retryCount;

                                        if (retryCount > maxRetryCount)
                                        {
                                            sqlex_on = false;
                                            RbTraceLog.WriteError("E001", ex.ToString(), jo_message);
                                        }
                                        else
                                        {
                                            RbTraceLog.WriteLog($"Transaction retry has started. Count({retryCount})");
                                            Thread.Sleep(sleepTime);
                                        }
                                    }
                                    else
                                    {
                                        RbTraceLog.WriteError("E001", ex.ToString(), jo_message);
                                    }
                                }
                                else
                                {
                                    RbTraceLog.WriteError("E001", ex.ToString(), jo_message);
                                }
                            }
                        }

                        if (!sqlex_on)
                        {
                            goto LoopExitLabel;
                        }
                    }

                    // Label - Loop exit
                    LoopExitLabel :;

                    if (rbTraceLevel == RbTraceType.Detail)
                    {
                        TimeSpan ts = DateTime.UtcNow - startDateTimeUtc;
                        RbTraceLog.WriteLog(string.Format("RoboticsEventProcessor Message processed.  Duration:{0}, Partition:{1}, DeviceId{2}, Message:{3}",
                                                          ts.ToString(), context.Lease.PartitionId, iothub_deviceId, text_message));
                    }
                }

                #endregion *** Handling unexpected exceptions ***
            }
            catch (Exception ex)
            {
                if (ex.Message == checkpointExMessage)
                {
                    RbTraceLog.WriteLog("** Retrying message processing because of CheckPointAsync error ** Info => "
                                        + ex.InnerException.ToString());
                }
                else
                {
                    RbTraceLog.WriteError("E999", ex.ToString());
                }
            }
        }
        CachedDllFileInfo CopyBlobToLocalDir(RbAppMasterCache rbappmc, RbAppRouterCache rbapprc, string partitionId)
        {
            //string curdir = Environment.CurrentDirectory;
            CachedDllFileInfo cachedDllFileInfo = new CachedDllFileInfo();
            string            curdir            = AppDomain.CurrentDomain.BaseDirectory;

            cachedDllFileInfo.BaseDirectory       = curdir;
            cachedDllFileInfo.PrivateDllDirectory = Path.Combine(curdir, "P" + partitionId);

            string            blobTargetFilePath     = string.Empty;
            RbAppDllCacheInfo rbAppDllInfo           = null;
            RbAppDllCacheInfo rbAppDllInfo_partition = null;
            bool   loadAction             = true;
            bool   blobCopyAction         = true;
            string partitionedFileNameKey = "P" + partitionId + "_" + rbapprc.FileName;

            // Check original DLL info
            if (rbAppDllCacheInfoDic.ContainsKey(rbapprc.FileName))
            {
                // Original DLL
                rbAppDllInfo       = (RbAppDllCacheInfo)rbAppDllCacheInfoDic[rbapprc.FileName];
                blobTargetFilePath = Path.Combine(rbAppDllInfo.CacheDir, rbAppDllInfo.CachedFileName);

                // Use cached original DLL if Registered_Datetime not changed.
                if (rbAppDllInfo.AppId == rbapprc.AppId &&
                    rbAppDllInfo.AppProcessingId == rbapprc.AppProcessingId &&
                    rbAppDllInfo.Registered_DateTime == rbapprc.Registered_DateTime)
                {
                    blobCopyAction = false;
                }
            }

            // Check partitioned DLL info
            if (rbAppDllCacheInfoDic.ContainsKey(partitionedFileNameKey))
            {
                // DLL copied into each partition directory
                rbAppDllInfo_partition = (RbAppDllCacheInfo)rbAppDllCacheInfoDic[partitionedFileNameKey];
                cachedDllFileInfo.PrivateDllFilePath = Path.Combine(rbAppDllInfo_partition.CacheDir, rbAppDllInfo_partition.CachedFileName);

                // Use cached DLL copied into each partition directory if Registered_Datetime not changed.
                if (rbAppDllInfo_partition.AppId == rbapprc.AppId &&
                    rbAppDllInfo_partition.AppProcessingId == rbapprc.AppProcessingId &&
                    rbAppDllInfo_partition.Registered_DateTime == rbapprc.Registered_DateTime)
                {
                    loadAction = false;
                }
            }

            if (loadAction)
            {
                if (blobTargetFilePath != string.Empty)
                {
                    AppDomain appDomain = null;
                    if (appDomainList.ContainsKey(partitionId))
                    {
                        appDomain = appDomainList[partitionId];
                        AppDomain.Unload(appDomain);
                        appDomainList[partitionId] = null;
                    }

                    if (blobCopyAction)
                    {
                        // Move current DLL to archive directory
                        if (File.Exists(blobTargetFilePath))
                        {
                            string archivedDirectory   = Path.Combine(curdir, archivedDirectoryName);
                            string archivedDllFilePath = archivedDirectory + @"\" + rbapprc.FileName
                                                         + ".bk" + DateTime.Now.ToString("yyyyMMddHHmmssfffffff");
                            if (!Directory.Exists(archivedDirectory))
                            {
                                Directory.CreateDirectory(archivedDirectory);
                            }
                            File.Move(blobTargetFilePath, archivedDllFilePath);
                        }
                    }
                }

                if (blobCopyAction)
                {
                    // Download DLL from BLOB
                    RbAzureStorage rbAzureStorage = new RbAzureStorage(rbappmc.StorageAccount, rbappmc.StorageKey);
                    rbAppDllInfo          = new RbAppDllCacheInfo();
                    rbAppDllInfo.FileName = rbapprc.FileName;
                    rbAppDllInfo.CacheDir = Path.Combine(curdir, "cache");
                    if (!Directory.Exists(rbAppDllInfo.CacheDir))
                    {
                        Directory.CreateDirectory(rbAppDllInfo.CacheDir);
                    }
                    rbAppDllInfo.AppId               = rbapprc.AppId;
                    rbAppDllInfo.AppProcessingId     = rbapprc.AppProcessingId;
                    rbAppDllInfo.Registered_DateTime = rbapprc.Registered_DateTime;
                    //rbAppDllInfo.GenerateCachedFileName();
                    rbAppDllInfo.CachedFileName = rbAppDllInfo.FileName;
                    blobTargetFilePath          = Path.Combine(rbAppDllInfo.CacheDir, rbAppDllInfo.CachedFileName);

                    using (var fileStream = File.OpenWrite(blobTargetFilePath))
                    {
                        rbAzureStorage.BlockBlobDownload(fileStream, rbapprc.BlobContainer, rbapprc.FileName);
                    }
                    // Update cache info if DLL download from BLOB is successful.
                    rbAppDllCacheInfoDic[rbapprc.FileName] = rbAppDllInfo;

                    // Logging
                    if (rbTraceLevel == RbTraceType.Detail)
                    {
                        RbTraceLog.WriteLog(string.Format("App DLL is copied from BLOB strage.  Dir:{0}, FileName:{1}",
                                                          curdir, rbAppDllInfo.CachedFileName));
                    }
                }

                // Copy original DLL into partition directory
                rbAppDllInfo_partition                     = new RbAppDllCacheInfo();
                rbAppDllInfo_partition.FileName            = rbapprc.FileName;
                rbAppDllInfo_partition.CacheDir            = cachedDllFileInfo.PrivateDllDirectory;
                rbAppDllInfo_partition.AppId               = rbapprc.AppId;
                rbAppDllInfo_partition.AppProcessingId     = rbapprc.AppProcessingId;
                rbAppDllInfo_partition.Registered_DateTime = rbapprc.Registered_DateTime;
                rbAppDllInfo_partition.CachedFileName      = rbAppDllInfo_partition.FileName;

                string sourceFilePath = Path.Combine(rbAppDllInfo.CacheDir, rbAppDllInfo.CachedFileName);
                string targetFilePath = Path.Combine(rbAppDllInfo_partition.CacheDir, rbAppDllInfo_partition.CachedFileName);
                cachedDllFileInfo.PrivateDllFilePath = targetFilePath;
                if (!Directory.Exists(rbAppDllInfo_partition.CacheDir))
                {
                    Directory.CreateDirectory(rbAppDllInfo_partition.CacheDir);
                }
                File.Copy(sourceFilePath, targetFilePath, true);

                // Update cache info if DLL copied successfully.
                rbAppDllCacheInfoDic[partitionedFileNameKey] = rbAppDllInfo_partition;

                // Logging
                if (rbTraceLevel == RbTraceType.Detail)
                {
                    RbTraceLog.WriteLog(string.Format("Original App DLL is copied into partition directory.  Dir:{0}, FileName:{1}, PartitionId:{2}",
                                                      curdir, rbAppDllInfo.CachedFileName, partitionId));
                }
            }

            return(cachedDllFileInfo);
        }
        JArray CallApps(RbHeader rbh, string rbBodyString, string partitionId)
        {
            // Get App Master Info
            RbAppMasterCache rbappmc = GetAppMasterInfo(rbh);

            // Get App Routing Info
            RbAppRouterCache rbapprc = GetAppRoutingInfo(rbh);

            JArrayString ja_messagesString = null;
            JArray       ja_messages       = null;
            string       dllFilePath       = string.Empty;

            IAppRouterDll routedAppDll = null;
            Assembly      assembly     = null;

            // Load DLL from BLOB
            string baseDirectory            = string.Empty;
            string privateDllDirectory      = string.Empty;
            string cachedFileName           = string.Empty;
            string cachedFileNameWithoutExt = string.Empty;

            if (rbapprc.DevMode == "True")
            {
                string devdir = rbapprc.DevLocalDir;
                int    pos    = devdir.Length - 1;
                if (devdir.Substring(pos, 1) == @"\")
                {
                    dllFilePath = rbapprc.DevLocalDir + rbapprc.FileName;
                }
                else
                {
                    dllFilePath = rbapprc.DevLocalDir + @"\" + rbapprc.FileName;
                }

                baseDirectory            = Path.GetDirectoryName(dllFilePath);
                privateDllDirectory      = baseDirectory;
                cachedFileName           = Path.GetFileName(dllFilePath);
                cachedFileNameWithoutExt = Path.GetFileNameWithoutExtension(dllFilePath);
            }
            else
            {
                CachedDllFileInfo cachedDllFileInfo = null;
                lock (thisLock2)
                {
                    cachedDllFileInfo = CopyBlobToLocalDir(rbappmc, rbapprc, partitionId);
                }
                baseDirectory            = cachedDllFileInfo.BaseDirectory;
                privateDllDirectory      = cachedDllFileInfo.PrivateDllDirectory;
                cachedFileName           = Path.GetFileName(cachedDllFileInfo.PrivateDllFilePath);
                cachedFileNameWithoutExt = Path.GetFileNameWithoutExtension(cachedDllFileInfo.PrivateDllFilePath);
            }

            ////Static load without AppDomain
            //assembly = System.Reflection.Assembly.LoadFrom(dllFilePath);
            //routedAppDll = assembly.CreateInstance(rbapprc.ClassName) as IAppRouterDll;

            //Dynamic load using AppDomain
            try
            {
                string    appDomainName = appDomanNameBase + partitionId;
                AppDomain appDomain     = null;
                if (appDomainList.ContainsKey(partitionId))
                {
                    appDomain = appDomainList[partitionId];
                }

                if (appDomain == null)
                {
                    appDomain = CreateAppDomain(appDomainName, baseDirectory, privateDllDirectory);
                    lock (thisLock2)
                    {
                        appDomainList[partitionId] = appDomain;
                    }
                }
                routedAppDll = appDomain.CreateInstanceAndUnwrap(cachedFileNameWithoutExt, rbapprc.ClassName) as IAppRouterDll;
            }
            catch (Exception ex)
            {
                RbTraceLog.WriteError("E003", ex.ToString());
                ae = new ApplicationException("Error ** Exception occured during creating AppDomain & Instance(App DLL)");
                throw ae;
            }

            // ProcessMessage
            try
            {
                rbh.ProcessingStack = rbapprc.FileName;
                ja_messagesString   = routedAppDll.ProcessMessage(rbappmc, rbapprc, rbh, rbBodyString);
                ja_messages         = ja_messagesString.ConvertToJArray();
            }
            catch (Exception ex)
            {
                RbTraceLog.WriteError("E002", ex.ToString());
                ae = new ApplicationException("Error ** Exception occured in routed App DLL");
                throw ae;
            }

            return(ja_messages);
        }