Ejemplo n.º 1
0
        public async Task <IActionResult> GetQueueLengthAsync()
        {
            // Manage session and Context
            HttpServiceUriBuilder contextUri = new HttpServiceUriBuilder().SetServiceName(this.context.ServiceName);
            string reportsSecretKey          = HTTPHelper.GetQueryParameterValueFor(HttpContext, Names.REPORTS_SECRET_KEY_NAME);
            long   count = 0;

            if ((reportsSecretKey.Length == 0) && HTTPHelper.IsSessionExpired(HttpContext, this))
            {
                return(Ok(contextUri.GetServiceNameSiteHomePath()));
            }
            else
            {
                ServiceUriBuilder uriBuilder = new ServiceUriBuilder(Names.InsightDataServiceName);
                Uri serviceUri = uriBuilder.Build();

                // service may be partitioned.
                // this will aggregate the queue lengths from each partition
                ServicePartitionList partitions = await this.fabricClient.QueryManager.GetPartitionListAsync(serviceUri);

                foreach (Partition partition in partitions)
                {
                    Uri getUrl = new HttpServiceUriBuilder()
                                 .SetServiceName(serviceUri)
                                 .SetPartitionKey(((Int64RangePartitionInformation)partition.PartitionInformation).LowKey)
                                 .SetServicePathAndQuery($"/api/devices/queue/length")
                                 .Build();

                    HttpResponseMessage response = await this.httpClient.GetAsync(getUrl, this.appLifetime.ApplicationStopping);

                    if (response.StatusCode != System.Net.HttpStatusCode.OK)
                    {
                        return(this.StatusCode((int)response.StatusCode));
                    }

                    string result = await response.Content.ReadAsStringAsync();

                    count += Int64.Parse(result);
                }
            }

            return(this.Ok(count));
        }
Ejemplo n.º 2
0
        public async Task <IActionResult> GetDevicesAsync()
        {
            ServiceUriBuilder uriBuilder = new ServiceUriBuilder(TenantDataServiceName);
            Uri serviceUri = uriBuilder.Build();

            // service may be partitioned.
            // this will aggregate device IDs from all partitions
            ServicePartitionList partitions = await this.fabricClient.QueryManager.GetPartitionListAsync(serviceUri);

            List <DeviceViewModel> deviceViewModels = new List <DeviceViewModel>();

            foreach (Partition partition in partitions)
            {
                Uri getUrl = new HttpServiceUriBuilder()
                             .SetServiceName(serviceUri)
                             .SetPartitionKey(((Int64RangePartitionInformation)partition.PartitionInformation).LowKey)
                             .SetServicePathAndQuery($"/api/devices")
                             .Build();

                HttpResponseMessage response = await this.httpClient.GetAsync(getUrl, this.serviceCancellationToken);

                if (response.StatusCode != System.Net.HttpStatusCode.OK)
                {
                    return(this.StatusCode((int)response.StatusCode));
                }

                JsonSerializer serializer = new JsonSerializer();
                using (StreamReader streamReader = new StreamReader(await response.Content.ReadAsStreamAsync()))
                {
                    using (JsonTextReader jsonReader = new JsonTextReader(streamReader))
                    {
                        List <DeviceViewModel> result = serializer.Deserialize <List <DeviceViewModel> >(jsonReader);

                        if (result != null)
                        {
                            deviceViewModels.AddRange(result);
                        }
                    }
                }
            }

            return(this.Ok(deviceViewModels));
        }
Ejemplo n.º 3
0
        public void SetAllTheThings()
        {
            HttpServiceUriBuilder target = new HttpServiceUriBuilder()
                                           .SetScheme("https")
                                           .SetHost("fabric")
                                           .SetServiceName("fabric:/app/service")
                                           .SetPartitionKey(34)
                                           .SetTarget(HttpServiceUriTarget.Secondary)
                                           .SetEndpointName("myendpoint")
                                           .SetServicePathAndQuery("path/to/nowhere?value=1");

            Assert.Equal <string>("https", target.Scheme);
            Assert.Equal <string>("fabric", target.Host);
            Assert.Equal <Uri>(new Uri("fabric:/app/service"), target.ServiceName);
            Assert.Equal <long>(34, (long)target.PartitionKey.Value);
            Assert.Equal <HttpServiceUriTarget>(HttpServiceUriTarget.Secondary, target.Target);
            Assert.Equal <string>("myendpoint", target.EndpointName);
            Assert.Equal <string>("path/to/nowhere?value=1", target.ServicePathAndQuery);
            Assert.Equal <string>("https:/fabric/app/service/#/34/secondary/myendpoint/path/to/nowhere?value=1", target.Build().ToString());
        }
Ejemplo n.º 4
0
        public async Task <string> DeleteTopic(string tenantId, string TopicName)
        {
            HttpResponseMessage responseMessage = new HttpResponseMessage(HttpStatusCode.InternalServerError);

            int reverseProxyPort = await FrontEndHelper.FrontEndHelper.GetReverseProxyPortAsync();

            HttpServiceUriBuilder builder = new HttpServiceUriBuilder()
            {
                PortNumber  = reverseProxyPort,
                ServiceName = $"{tenantId}/{TenantApplicationAdminServiceName}/api/topics/" + TopicName
            };

            HttpResponseMessage topicResponseMessage;

            using (HttpClient httpClient = new HttpClient())
            {
                topicResponseMessage = await httpClient.DeleteAsync(builder.Build());
            }

            return("deleted");
        }
        // TODO: 3.1
        public async Task <IActionResult> Index()
        {
            var partitions = await fabricClient.QueryManager.GetPartitionListAsync(backServiceUri);

            var orderTasks = new List <Task <List <OrderModel> > >();

            foreach (var partition in partitions)
            {
                async Task <List <OrderModel> > queryPartition()
                {
                    var getUrl = new HttpServiceUriBuilder()
                                 .SetServiceName(backServiceUri)
                                 .SetPartitionKey(((Int64RangePartitionInformation)partition.PartitionInformation).LowKey)
                                 .SetEndpointName("KestrelListener")
                                 .SetServicePathAndQuery("/api/orders")
                                 .Build();

                    var response = await httpClient.GetAsync(getUrl, applicationLifetime.ApplicationStopping);

                    if (response.StatusCode != System.Net.HttpStatusCode.OK)
                    {
                        return(new List <OrderModel>());
                    }

                    var json = await response.Content.ReadAsStringAsync();

                    return(JsonConvert.DeserializeObject <List <OrderModel> >(json));
                }

                orderTasks.Add(queryPartition());
            }

            var allPartitionOrders = await Task.WhenAll(orderTasks);

            return(View(new IndexViewModel
            {
                Orders = allPartitionOrders.SelectMany(o => o)
            }));
        }
Ejemplo n.º 6
0
        public async Task <string> CreateTopic(string tenantId, string TopicName)
        {
            //var key = HttpContext.Current.Request.Headers.GetValues("x-request-key").FirstOrDefault();

            HttpResponseMessage responseMessage = new HttpResponseMessage(HttpStatusCode.InternalServerError);

            int reverseProxyPort = await FrontEndHelper.FrontEndHelper.GetReverseProxyPortAsync();

            HttpServiceUriBuilder builder = new HttpServiceUriBuilder()
            {
                PortNumber  = reverseProxyPort,
                ServiceName = $"{tenantId}/{TenantApplicationAdminServiceName}/api/topics/" + TopicName
            };

            HttpResponseMessage topicResponseMessage;

            using (HttpClient httpClient = new HttpClient())
            {
                topicResponseMessage = await httpClient.PutAsync(builder.Build(), null);
            }

            return("created");
        }
Ejemplo n.º 7
0
        public async Task <IActionResult> Order()
        {
            Uri putUrl = new HttpServiceUriBuilder()
                         .SetServiceName(backServiceUri)
                         .SetEndpointName("KestrelListener")
                         .SetServicePathAndQuery("/api/orders")
                         .Build();

            var newOrder = new NewOrderRequest {
                SubmittedOn = DateTime.UtcNow, OrderId = CombGuid.Generate()
            };

            using (var content = new StringContent(JsonConvert.SerializeObject(newOrder), Encoding.UTF8, "application/json"))
            {
                var httpResponse = await httpClient.PutAsync(putUrl, content)
                                   .ConfigureAwait(false);

                var json = await httpResponse.Content.ReadAsStringAsync();

                var model = JsonConvert.DeserializeObject <OrderViewModel>(json);

                return(View(model));
            }
        }
        public async Task <IActionResult> GetDevicesAsync(string deviceId = null)
        {
            // Manage session and Context
            HttpServiceUriBuilder contextUri       = new HttpServiceUriBuilder().SetServiceName(this.context.ServiceName);
            string reportsSecretKey                = HTTPHelper.GetQueryParameterValueFor(HttpContext, Names.REPORTS_SECRET_KEY_NAME);
            List <DeviceMessage> deviceMessageList = new List <DeviceMessage>();

            if ((reportsSecretKey.Length == 0) && HTTPHelper.IsSessionExpired(HttpContext, this))
            {
                return(Ok(contextUri.GetServiceNameSiteHomePath()));
            }
            else if (reportsSecretKey.Length > 0)
            {
                // simply return some empty answer - no indication of error for security reasons
                if (!reportsSecretKey.Equals(Names.REPORTS_SECRET_KEY_VALUE))
                {
                    return(this.Ok(deviceMessageList));
                }
            }

            deviceMessageList = await GetDevicesDataAsync(deviceId, this.httpClient, this.fabricClient, this.appLifetime);

            return(this.Ok(deviceMessageList));
        }
Ejemplo n.º 9
0
        public ActionResult Login(UserProfile objUser)
        {
            // Manage session and Context
            HttpServiceUriBuilder contextUri = new HttpServiceUriBuilder().SetServiceName(this.context.ServiceName);

            if (ModelState.IsValid)
            {
                ViewBag.Message     = "";
                ViewBag.RedirectURL = "";
                bool newUserRegistration = false;
                bool userAllowedToLogin  = false;

                if ((objUser.Password != null && objUser.Password.Length > 0))
                {
                    // First let deal to see if this a user registration
                    if (objUser.FirstName != null)
                    {
                        newUserRegistration = true;
                        Task <bool> result = RESTHandler.ExecuteFabricPOSTForEntity(typeof(UserProfile),
                                                                                    Names.InsightDataServiceName,
                                                                                    "api/entities/user/withIdentity/" + objUser.UserName,
                                                                                    "user",
                                                                                    objUser,
                                                                                    this.context,
                                                                                    this.httpClient,
                                                                                    this.appLifetime.ApplicationStopping,
                                                                                    ServiceEventSource.Current);
                        if (result.Result)
                        {
                            userAllowedToLogin = true;
                        }
                        else
                        {
                            ViewBag.RedirectURL = contextUri.GetServiceNameSiteHomePath();
                            ViewBag.Message     = "Error during new user registration - User already exist in the database";
                        }
                    }

                    if (!userAllowedToLogin && !newUserRegistration)
                    {
                        Task <object> userObject = RESTHandler.ExecuteFabricGETForEntity(typeof(UserProfile),
                                                                                         Names.InsightDataServiceName,
                                                                                         "api/entities/user/byIdentity/" + objUser.UserName,
                                                                                         "user",
                                                                                         this.context,
                                                                                         this.httpClient,
                                                                                         this.appLifetime.ApplicationStopping,
                                                                                         ServiceEventSource.Current);
                        if (userObject != null)
                        {
                            UserProfile userProfile = (UserProfile)userObject.Result;

                            if (objUser.Password.Equals(userProfile.Password))
                            {
                                userAllowedToLogin = true;
                            }
                            else
                            {
                                ViewBag.RedirectURL = contextUri.GetServiceNameSiteHomePath();
                                ViewBag.Message     = "Invalid Username and/or Password";
                            }
                        }
                        else
                        {
                            ViewBag.RedirectURL = contextUri.GetServiceNameSiteHomePath();
                            ViewBag.Message     = "Error checking user credentials";
                        }
                    }

                    if (userAllowedToLogin)
                    {
                        try
                        {
                            string redirectTo = HTTPHelper.StartSession(HttpContext, this, objUser, "User", "/api/devices", contextUri.GetServiceNameSiteHomePath());

                            //TODO : make the redirection configurable as part of insight application
                            return(Redirect(redirectTo));
                        }
                        catch (System.Exception ex)
                        {
                            ViewBag.RedirectURL = contextUri.GetServiceNameSiteHomePath();
                            ViewBag.Message     = "Internal Error During User Login- Report to the System Administrator";
                            Console.WriteLine("On Login Session exception msg=[" + ex.Message + "]");
                        }
                    }
                }
                else
                {
                    ViewBag.RedirectURL = contextUri.GetServiceNameSiteHomePath();
                    ViewBag.Message     = "Either username and/or password not provided";
                }
            }

            if (!HTTPHelper.IsSessionExpired(HttpContext, this))
            {
                HTTPHelper.EndSession(HttpContext, this);
            }

            return(View("Index", objUser));
        }
Ejemplo n.º 10
0
        public void ConstructorGetServicePathAndQuery()
        {
            HttpServiceUriBuilder target = new HttpServiceUriBuilder("http://fabric/App/Service/Name/1/2/3/#/Partitionkey/any/endpoint-name/my/service/url?value=1");

            Assert.Equal <string>("my/service/url?value=1", target.ServicePathAndQuery);
        }
Ejemplo n.º 11
0
        public void ConstructorGetScheme()
        {
            HttpServiceUriBuilder target = new HttpServiceUriBuilder("http://fabric/App/Service/#/partitionkey/any/endpoint-name/api-path");

            Assert.Equal <string>("http", target.Scheme);
        }
Ejemplo n.º 12
0
        public void ConstructorGetTarget(HttpServiceUriTarget expectedTarget, string url)
        {
            HttpServiceUriBuilder target = new HttpServiceUriBuilder(url);

            Assert.Equal <HttpServiceUriTarget>(expectedTarget, target.Target);
        }
Ejemplo n.º 13
0
        public void ConstructorGetEndpointName()
        {
            HttpServiceUriBuilder target = new HttpServiceUriBuilder("http://fabric/App/Service/Name/1/2/3/#/Partitionkey/any/endpoint-name/api-path");

            Assert.Equal <string>("endpoint-name", target.EndpointName);
        }
    /// <summary>
    /// http://fabric/app/service/#/partitionkey/any|primary|secondary/endpoint-name/api-path
    /// </summary>
    /// <param name="request"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        ServicePartitionResolver resolver   = ServicePartitionResolver.GetDefault();
        ResolvedServicePartition partition  = null;
        HttpServiceUriBuilder    uriBuilder = new HttpServiceUriBuilder(request.RequestUri);

        int  retries        = MaxRetries;
        int  retryDelay     = InitialRetryDelayMs;
        bool resolveAddress = true;

        HttpResponseMessage lastResponse  = null;
        Exception           lastException = null;

        while (retries-- > 0)
        {
            lastResponse = null;
            cancellationToken.ThrowIfCancellationRequested();

            if (resolveAddress)
            {
                partition = partition != null
                    ? await resolver.ResolveAsync(partition, cancellationToken)
                    : await resolver.ResolveAsync(uriBuilder.ServiceName, uriBuilder.PartitionKey, cancellationToken);

                string serviceEndpointJson;

                switch (uriBuilder.Target)
                {
                case HttpServiceUriTarget.Default:
                case HttpServiceUriTarget.Primary:
                    serviceEndpointJson = partition.GetEndpoint().Address;
                    break;

                case HttpServiceUriTarget.Secondary:
                    serviceEndpointJson = partition.Endpoints.ElementAt(this.random.Next(1, partition.Endpoints.Count)).Address;
                    break;

                case HttpServiceUriTarget.Any:
                default:
                    serviceEndpointJson = partition.Endpoints.ElementAt(this.random.Next(0, partition.Endpoints.Count)).Address;
                    break;
                }

                string endpointUrl = JObject.Parse(serviceEndpointJson)["Endpoints"][uriBuilder.EndpointName].Value <string>();

                request.RequestUri = new Uri($"{endpointUrl.TrimEnd('/')}/{uriBuilder.ServicePathAndQuery.TrimStart('/')}", UriKind.Absolute);
            }

            try
            {
                lastResponse = await base.SendAsync(request, cancellationToken);

                if (lastResponse.StatusCode == HttpStatusCode.NotFound ||
                    lastResponse.StatusCode == HttpStatusCode.ServiceUnavailable)
                {
                    resolveAddress = true;
                }
                else
                {
                    return(lastResponse);
                }
            }
            catch (TimeoutException te)
            {
                lastException  = te;
                resolveAddress = true;
            }
            catch (SocketException se)
            {
                lastException  = se;
                resolveAddress = true;
            }
            catch (HttpRequestException hre)
            {
                lastException  = hre;
                resolveAddress = true;
            }
            catch (Exception ex)
            {
                lastException = ex;
                WebException we = ex as WebException;

                if (we == null)
                {
                    we = ex.InnerException as WebException;
                }

                if (we != null)
                {
                    HttpWebResponse errorResponse = we.Response as HttpWebResponse;

                    // the following assumes port sharing
                    // where a port is shared by multiple replicas within a host process using a single web host (e.g., http.sys).
                    if (we.Status == WebExceptionStatus.ProtocolError)
                    {
                        if (errorResponse.StatusCode == HttpStatusCode.NotFound ||
                            errorResponse.StatusCode == HttpStatusCode.ServiceUnavailable)
                        {
                            // This could either mean we requested an endpoint that does not exist in the service API (a user error)
                            // or the address that was resolved by fabric client is stale (transient runtime error) in which we should re-resolve.
                            resolveAddress = true;
                        }

                        // On any other HTTP status codes, re-throw the exception to the caller.
                        throw;
                    }

                    if (we.Status == WebExceptionStatus.Timeout ||
                        we.Status == WebExceptionStatus.RequestCanceled ||
                        we.Status == WebExceptionStatus.ConnectionClosed ||
                        we.Status == WebExceptionStatus.ConnectFailure)
                    {
                        resolveAddress = true;
                    }
                }
                else
                {
                    throw;
                }
            }

            await Task.Delay(retryDelay);

            retryDelay += retryDelay;
        }

        if (lastResponse != null)
        {
            return(lastResponse);
        }
        else
        {
            throw lastException;
        }
    }
Ejemplo n.º 15
0
        public void ConstructorGetPartitionKey()
        {
            HttpServiceUriBuilder target = new HttpServiceUriBuilder("http://fabric/App/Service/Name/1/2/3/#/Partitionkey/any/endpoint-name/api-path");

            Assert.Equal <string>("Partitionkey", target.PartitionKey.Value as string);
        }
Ejemplo n.º 16
0
        public void ConstructorGetServiceName()
        {
            HttpServiceUriBuilder target = new HttpServiceUriBuilder("http://fabric/App/Service/Name/1/2/3/#/partitionkey/any/endpoint-name/api-path");

            Assert.Equal <Uri>(new Uri("fabric:/App/Service/Name/1/2/3"), target.ServiceName);
        }
        public async Task <IActionResult> GetDevicesHistoryByInterval(int startHours, int endHours, string deviceId = null, int limit = Int32.MaxValue, int minMagnitudeAllowed = 1)
        {
            // Manage session and Context
            HttpServiceUriBuilder contextUri = new HttpServiceUriBuilder().SetServiceName(this.context.ServiceName);
            string reportsSecretKey          = HTTPHelper.GetQueryParameterValueFor(HttpContext, Names.REPORTS_SECRET_KEY_NAME);
            List <DeviceHistoricalReportModel> deviceHistoricalReportModelList = new List <DeviceHistoricalReportModel>();

            long searchIntervalStart = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - DateTimeOffset.UtcNow.AddHours(startHours * (-1)).ToUnixTimeMilliseconds();
            long searchIntervalEnd   = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - DateTimeOffset.UtcNow.AddHours(endHours * (-1)).ToUnixTimeMilliseconds();

            ServiceUriBuilder uriBuilder = new ServiceUriBuilder(Names.InsightDataServiceName);
            Uri serviceUri = uriBuilder.Build();

            // service may be partitioned.
            // this will aggregate device IDs from all partitions
            ServicePartitionList partitions = await fabricClient.QueryManager.GetPartitionListAsync(serviceUri);

            foreach (Partition partition in partitions)
            {
                String pathAndQuery = $"/api/devices/history/interval/{searchIntervalStart}/{searchIntervalEnd}/limit/{limit}";

                if (deviceId != null && deviceId.Length > 0)
                {
                    pathAndQuery = $"/api/devices/history/{deviceId}/interval/{searchIntervalStart}/{searchIntervalEnd}/limit/{limit}";
                }

                Uri getUrl = new HttpServiceUriBuilder()
                             .SetServiceName(serviceUri)
                             .SetPartitionKey(((Int64RangePartitionInformation)partition.PartitionInformation).LowKey)
                             .SetServicePathAndQuery(pathAndQuery)
                             .Build();

                HttpResponseMessage response = await httpClient.GetAsync(getUrl, appLifetime.ApplicationStopping);

                if (response.StatusCode == System.Net.HttpStatusCode.OK)
                {
                    JsonSerializer serializer = new JsonSerializer();
                    using (StreamReader streamReader = new StreamReader(await response.Content.ReadAsStreamAsync()))
                    {
                        using (JsonTextReader jsonReader = new JsonTextReader(streamReader))
                        {
                            List <DeviceViewModelList> deviceViewModelListResult = serializer.Deserialize <List <DeviceViewModelList> >(jsonReader);

                            string                uniqueId      = FnvHash.GetUniqueId();
                            List <string>         deviceList    = new List <string>();
                            List <DateTimeOffset> timestampList = new List <DateTimeOffset>();
                            foreach (DeviceViewModelList deviceViewModelList in deviceViewModelListResult)
                            {
                                int deviceIdIndex = 0;

                                if (deviceList.Contains(deviceViewModelList.DeviceId))
                                {
                                    deviceIdIndex = deviceList.IndexOf(deviceViewModelList.DeviceId);
                                }
                                else
                                {
                                    deviceList.Add(deviceViewModelList.DeviceId);
                                    deviceIdIndex = deviceList.IndexOf(deviceViewModelList.DeviceId);
                                }

                                int timesampIndex = 0;

                                if (timestampList.Contains(deviceViewModelList.Events.ElementAt(0).Timestamp))
                                {
                                    timesampIndex = timestampList.IndexOf(deviceViewModelList.Events.ElementAt(0).Timestamp);
                                }
                                else
                                {
                                    timestampList.Add(deviceViewModelList.Events.ElementAt(0).Timestamp);
                                    timesampIndex = timestampList.IndexOf(deviceViewModelList.Events.ElementAt(0).Timestamp);
                                }

                                int batteryVoltage    = deviceViewModelList.Events.ElementAt(0).BatteryLevel / 1000;
                                int batteryPercentage = 0;

                                if (deviceViewModelList.Events.ElementAt(0).BatteryLevel < 2800)
                                {
                                    batteryPercentage = 0;
                                }
                                else if (deviceViewModelList.Events.ElementAt(0).BatteryLevel > 3600)
                                {
                                    batteryPercentage = 100;
                                }
                                else
                                {
                                    batteryPercentage = (deviceViewModelList.Events.ElementAt(0).BatteryLevel - 2800) / 10;
                                }

                                int  minAllowedFrequency = 0;
                                bool needReferencEntry   = true;
                                foreach (DeviceViewModel evnt in deviceViewModelList.Events)
                                {
                                    for (int index = 0; index < evnt.DataPointsCount; index++)
                                    {
                                        if (evnt.Magnitude[index] >= minMagnitudeAllowed)
                                        {
                                            needReferencEntry = false;
                                            DeviceHistoricalReportModel message = new DeviceHistoricalReportModel(
                                                uniqueId,
                                                evnt.Timestamp,
                                                timesampIndex,
                                                evnt.DeviceId,
                                                deviceIdIndex,
                                                evnt.BatteryLevel,
                                                batteryVoltage,
                                                batteryPercentage,
                                                evnt.TempExternal,
                                                evnt.TempInternal,
                                                evnt.DataPointsCount,
                                                evnt.MeasurementType,
                                                evnt.SensorIndex,
                                                evnt.Frequency[index],
                                                evnt.Magnitude[index]);
                                            deviceHistoricalReportModelList.Add(message);

                                            if (minAllowedFrequency == 0)
                                            {
                                                minAllowedFrequency = evnt.Frequency[index];
                                            }
                                        }
                                    }
                                }

                                if (needReferencEntry)
                                {
                                    DeviceHistoricalReportModel message = new DeviceHistoricalReportModel(
                                        uniqueId,
                                        deviceViewModelList.Events.ElementAt(0).Timestamp,
                                        timesampIndex,
                                        deviceViewModelList.Events.ElementAt(0).DeviceId,
                                        deviceIdIndex,
                                        deviceViewModelList.Events.ElementAt(0).BatteryLevel,
                                        batteryVoltage,
                                        batteryPercentage,
                                        deviceViewModelList.Events.ElementAt(0).TempExternal,
                                        deviceViewModelList.Events.ElementAt(0).TempInternal,
                                        deviceViewModelList.Events.ElementAt(0).DataPointsCount,
                                        deviceViewModelList.Events.ElementAt(0).MeasurementType,
                                        deviceViewModelList.Events.ElementAt(0).SensorIndex,
                                        minAllowedFrequency,
                                        minMagnitudeAllowed);
                                    deviceHistoricalReportModelList.Add(message);
                                }
                            }
                        }
                    }
                }
            }

            return(this.Ok(deviceHistoricalReportModelList));
        }
Ejemplo n.º 18
0
        public async Task <IActionResult> EmbedReport(string reportName, string reportParm = null, string reportParmStart = null, string reportParmEnd = null, int numberOfObservations = (-1), int minMagnitudeAllowed = 1)
        {
            // Manage session and Context
            HttpServiceUriBuilder contextUri = new HttpServiceUriBuilder().SetServiceName(this.context.ServiceName);

            ViewBag.RedirectURL = "";

            if (HTTPHelper.IsSessionExpired(HttpContext, this))
            {
                return(Ok(contextUri.GetServiceNameSiteHomePath()));
            }
            else
            {
                this.ViewData["TargetSite"]  = contextUri.GetServiceNameSite();
                this.ViewData["PageTitle"]   = "Report";
                this.ViewData["HeaderTitle"] = "Last Posted Events";

                string reportUniqueId = FnvHash.GetUniqueId();

                // Now it is time to refresh the data set
                List <DeviceViewModelList> deviceViewModelList = null;
                int  resampleSetsLimit = 0;
                var  refreshDataresult = false;
                bool publishReportData = true;

                if (reportName.Equals("PSG-VibrationDeviceReport-02"))
                {
                    refreshDataresult = true;
                    publishReportData = false;
                }
                else if (reportName.Equals("PSG-VibrationDeviceReport-01") && reportParm != null)
                {
                    deviceViewModelList = await DevicesController.GetDevicesDataAsync(reportParm, httpClient, fabricClient, appLifetime);
                }
                else
                {
                    resampleSetsLimit = 1;

                    deviceViewModelList = new List <DeviceViewModelList>();
                    ServiceUriBuilder uriBuilder = new ServiceUriBuilder(Names.InsightDataServiceName);
                    Uri serviceUri = uriBuilder.Build();

                    // service may be partitioned.
                    // this will aggregate device IDs from all partitions
                    ServicePartitionList partitions = await fabricClient.QueryManager.GetPartitionListAsync(serviceUri);

                    foreach (Partition partition in partitions)
                    {
                        string pathAndQuery      = null;
                        int    index             = 0;
                        float  indexInterval     = 1F;
                        bool   keepLooping       = true;
                        int    observationsCount = 0;
                        int    batchIndex        = 0;
                        int    batchSize         = 10000;


                        while (keepLooping)
                        {
                            if (reportParmEnd == null)
                            {
                                pathAndQuery = $"/api/devices/history/byKey/{reportParmStart}";
                                keepLooping  = false;
                            }
                            else if (numberOfObservations != (-1))
                            {
                                pathAndQuery = $"/api/devices/history/byKeyRange/{reportParmStart}/{reportParmEnd}/{batchIndex}/{batchSize}";

                                if (index == 0)
                                {
                                    string getCountPathAndQuery = $"/api/devices/history/count/interval/{reportParmStart}/{reportParmEnd}";
                                    Uri    getCountUrl          = new HttpServiceUriBuilder()
                                                                  .SetServiceName(serviceUri)
                                                                  .SetPartitionKey(((Int64RangePartitionInformation)partition.PartitionInformation).LowKey)
                                                                  .SetServicePathAndQuery(getCountPathAndQuery)
                                                                  .Build();

                                    HttpResponseMessage localResponse = await httpClient.GetAsync(getCountUrl, appLifetime.ApplicationStopping);

                                    if (localResponse.StatusCode == System.Net.HttpStatusCode.OK)
                                    {
                                        string localResult = await localResponse.Content.ReadAsStringAsync();

                                        long count = Int64.Parse(localResult);

                                        indexInterval = count / numberOfObservations;

                                        if (indexInterval < 1)
                                        {
                                            indexInterval = 1;
                                        }
                                    }
                                }
                            }
                            else if (reportParmEnd != null)
                            {
                                pathAndQuery = $"/api/devices/history/byKeyRange/{reportParmStart}/{reportParmEnd}";
                                keepLooping  = false;
                            }

                            Uri getUrl = new HttpServiceUriBuilder()
                                         .SetServiceName(serviceUri)
                                         .SetPartitionKey(((Int64RangePartitionInformation)partition.PartitionInformation).LowKey)
                                         .SetServicePathAndQuery(pathAndQuery)
                                         .Build();

                            HttpResponseMessage response = await httpClient.GetAsync(getUrl, appLifetime.ApplicationStopping);

                            if (response.StatusCode == System.Net.HttpStatusCode.OK)
                            {
                                JsonSerializer serializer = new JsonSerializer();
                                using (StreamReader streamReader = new StreamReader(await response.Content.ReadAsStreamAsync()))
                                {
                                    using (JsonTextReader jsonReader = new JsonTextReader(streamReader))
                                    {
                                        List <DeviceViewModelList> localResult = serializer.Deserialize <List <DeviceViewModelList> >(jsonReader);

                                        if (localResult != null)
                                        {
                                            if (localResult.Count != 0)
                                            {
                                                foreach (DeviceViewModelList device in localResult)
                                                {
                                                    if (index >= (observationsCount * indexInterval))
                                                    {
                                                        deviceViewModelList.Add(device);
                                                        observationsCount++;
                                                    }
                                                    index++;

                                                    if (numberOfObservations != (-1))
                                                    {
                                                        if (observationsCount == numberOfObservations)
                                                        {
                                                            keepLooping = false;
                                                            break;
                                                        }
                                                    }
                                                }
                                            }
                                            else
                                            {
                                                keepLooping = false;
                                            }
                                        }
                                        else
                                        {
                                            keepLooping = false;
                                        }
                                    }
                                }
                            }
                            batchIndex += batchSize;
                        }
                    }
                }

                if (publishReportData)
                {
                    refreshDataresult = await ReportsHandler.PublishReportDataFor(reportUniqueId, DevicesDataStream01URL, deviceViewModelList, context, httpClient, appLifetime.ApplicationStopping, ServiceEventSource.Current, resampleSetsLimit, minMagnitudeAllowed);
                }

                if (reportName.Equals("PSG-VibrationDeviceReport-02"))
                {
                    reportUniqueId = "";
                }

                EmbedConfig task = await ReportsHandler.GetEmbedReportConfigData(ClientId, GroupId, Username, Password, AuthorityUrl, ResourceUrl, ApiUrl, reportUniqueId, reportName, this.context, ServiceEventSource.Current);

                this.ViewData["EmbedToken"]     = task.EmbedToken.Token;
                this.ViewData["EmbedURL"]       = task.EmbedUrl;
                this.ViewData["EmbedId"]        = task.Id;
                this.ViewData["ReportUniqueId"] = reportUniqueId;

                return(this.View());
            }
        }
        public async Task <PhysicalFileResult> SearchDevicesHistoryForDownload(string startTimestamp, string endTimestamp, string deviceId = null)
        {
            string bodyPrefix    = "[";
            string bodySuffix    = "]";
            string bodySeparator = ",";
            bool   firstElement  = true;
            string fileName      = Path.GetTempFileName();

            byte[] contentArray;
            int    bufferSize = 4096;

            using (var fileStream = System.IO.File.Create(fileName, bufferSize))
            {
                contentArray = Encoding.ASCII.GetBytes(bodyPrefix);
                fileStream.Write(contentArray, 0, contentArray.Length);

                // Manage session and Context
                HttpServiceUriBuilder contextUri = new HttpServiceUriBuilder().SetServiceName(this.context.ServiceName);

                ServiceUriBuilder uriBuilder = new ServiceUriBuilder(Names.InsightDataServiceName);
                Uri serviceUri = uriBuilder.Build();

                // service may be partitioned.
                // this will aggregate the queue lengths from each partition
                ServicePartitionList partitions = await this.fabricClient.QueryManager.GetPartitionListAsync(serviceUri);

                foreach (Partition partition in partitions)
                {
                    bool keepLooping = true;
                    int  indexStart  = 0;
                    int  batchSize   = 200;

                    while (keepLooping)
                    {
                        string pathAndQuery = $"/api/devices/history/byKeyRange/{startTimestamp}/{endTimestamp}/{indexStart}/{batchSize}";

                        Uri getUrl = new HttpServiceUriBuilder()
                                     .SetServiceName(serviceUri)
                                     .SetPartitionKey(((Int64RangePartitionInformation)partition.PartitionInformation).LowKey)
                                     .SetServicePathAndQuery(pathAndQuery)
                                     .Build();

                        HttpResponseMessage response = await httpClient.GetAsync(getUrl, appLifetime.ApplicationStopping);

                        if (response.StatusCode == System.Net.HttpStatusCode.OK)
                        {
                            JsonSerializer serializer = new JsonSerializer();
                            using (StreamReader streamReader = new StreamReader(await response.Content.ReadAsStreamAsync()))
                            {
                                using (JsonTextReader jsonReader = new JsonTextReader(streamReader))
                                {
                                    List <DeviceMessage> localResult = serializer.Deserialize <List <DeviceMessage> >(jsonReader);

                                    if (localResult != null)
                                    {
                                        if (localResult.Count > 0)
                                        {
                                            foreach (DeviceMessage device in localResult)
                                            {
                                                foreach (DeviceEvent deviceEvent in device.Events)
                                                {
                                                    if (firstElement)
                                                    {
                                                        firstElement = false;
                                                    }
                                                    else
                                                    {
                                                        contentArray = Encoding.ASCII.GetBytes(bodySeparator);
                                                        fileStream.Write(contentArray, 0, contentArray.Length);
                                                    }

                                                    string objectContent = JsonConvert.SerializeObject(deviceEvent);

                                                    contentArray = Encoding.ASCII.GetBytes(objectContent);
                                                    fileStream.Write(contentArray, 0, contentArray.Length);
                                                }
                                            }
                                        }
                                        else
                                        {
                                            keepLooping = false;
                                        }
                                    }
                                    else
                                    {
                                        keepLooping = false;
                                    }
                                }
                            }
                        }

                        indexStart += batchSize;
                    }
                    contentArray = Encoding.ASCII.GetBytes(bodySuffix);
                    fileStream.Write(contentArray, 0, contentArray.Length);

                    fileStream.Flush(true);

                    Response.Headers["content-disposition"] = "attachment; filename= export.json";
                    Response.ContentType = "text/json";
                }
                return(PhysicalFile(fileName, "text/json", "export.json"));
            }
        }
        /// <summary>
        /// This is the main entry point for your service replica.
        /// This method executes when this replica of your service becomes primary and has write status.
        /// </summary>
        /// <param name="cancellationToken">Canceled when Service Fabric needs to shut down this service replica.</param>
        protected override async Task RunAsync(CancellationToken cancellationToken)
        {
            // Get the IoT Hub connection string from the Settings.xml config file
            // from a configuration package named "Config"
            string iotHubConnectionString =
                this.Context.CodePackageActivationContext
                .GetConfigurationPackageObject("Config")
                .Settings
                .Sections["IoTHubConfigInformation"]
                .Parameters["ConnectionString"]
                .Value;

            // 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;

            EventHubReceiver eventHubReceiver = null;
            MessagingFactory messagingFactory = null;

            try
            {
                // Get an EventHubReceiver and the MessagingFactory used to create it.
                // The EventHubReceiver is used to get events from IoT Hub.
                // The MessagingFactory is just saved for later so it can be closed before RunAsync exits.
                Tuple <EventHubReceiver, MessagingFactory> iotHubInfo =
                    await this.ConnectToIoTHubAsync(iotHubConnectionString, servicePartitionKey, epochDictionary, offsetDictionary);

                eventHubReceiver = iotHubInfo.Item1;
                messagingFactory = iotHubInfo.Item2;

                // HttpClient is designed as a shared object.
                // A single instance should be used throughout the lifetime of RunAsync.
                using (HttpClient httpClient = new HttpClient(new HttpServiceClientHandler()))
                {
                    int offsetIteration = 0;

                    while (true)
                    {
                        cancellationToken.ThrowIfCancellationRequested();

                        try
                        {
                            // It's important to set a low wait time here in lieu of a cancellation token
                            // so that this doesn't block RunAsync from exiting when Service Fabric needs it to complete.
                            // ReceiveAsync is a long-poll operation, so the timeout should not be too low,
                            // yet not too high to block RunAsync from exiting within a few seconds.
                            using (EventData eventData = await eventHubReceiver.ReceiveAsync(TimeSpan.FromSeconds(5)))
                            {
                                if (eventData == null)
                                {
                                    continue;
                                }

                                string tenantId = (string)eventData.Properties["TenantID"];
                                string deviceId = (string)eventData.Properties["DeviceID"];

                                // This is the named service instance of the tenant data service that the event should be sent to.
                                // The tenant ID is part of the named service instance name.
                                // The incoming device data stream specifie which tenant the data belongs to.
                                Uri  tenantServiceName         = new Uri($"{Names.InsightApplicationNamePrefix}/{tenantId}/{Names.InsightDataServiceName}");
                                long tenantServicePartitionKey = FnvHash.Hash(deviceId);

                                // The tenant data service exposes an HTTP API.
                                // For incoming device events, the URL is /api/events/{deviceId}
                                // This sets up a URL and sends a POST request with the device JSON payload.
                                Uri postUrl = new HttpServiceUriBuilder()
                                              .SetServiceName(tenantServiceName)
                                              .SetPartitionKey(tenantServicePartitionKey)
                                              .SetServicePathAndQuery($"/api/events/{deviceId}")
                                              .Build();

                                // The device stream payload isn't deserialized and buffered in memory here.
                                // Instead, we just can just hook the incoming stream from Iot Hub right into the HTTP request stream.
                                using (Stream eventStream = eventData.GetBodyStream())
                                {
                                    using (StreamContent postContent = new StreamContent(eventStream))
                                    {
                                        postContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");

                                        HttpResponseMessage response = await httpClient.PostAsync(postUrl, postContent, cancellationToken);

                                        ServiceEventSource.Current.ServiceMessage(
                                            this.Context,
                                            "Sent event data to insight service '{0}' with partition key '{1}'. Result: {2}",
                                            tenantServiceName,
                                            tenantServicePartitionKey,
                                            response.StatusCode.ToString());

                                        if (response.StatusCode == System.Net.HttpStatusCode.BadRequest)
                                        {
                                            // This service expects the receiving tenant service to return HTTP 400 if the device message was malformed.
                                            // In this example, the message is simply logged.
                                            // Your application should handle all possible error status codes from the receiving service
                                            // and treat the message as a "poison" message.
                                            // Message processing should be allowed to continue after a poison message is detected.

                                            string responseContent = await response.Content.ReadAsStringAsync();

                                            ServiceEventSource.Current.ServiceMessage(
                                                this.Context,
                                                "Insight service '{0}' returned HTTP 400 due to a bad device message from device '{1}'. Error message: '{2}'",
                                                tenantServiceName,
                                                deviceId,
                                                responseContent);
                                        }
                                    }
                                }

                                // 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.
                                if (++offsetIteration % OffsetInterval == 0)
                                {
                                    ServiceEventSource.Current.ServiceMessage(
                                        this.Context,
                                        "Saving offset {0}",
                                        eventData.Offset);

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

                                        await tx.CommitAsync();
                                    }

                                    offsetIteration = 0;
                                }
                            }
                        }
                        catch (TimeoutException te)
                        {
                            // transient error. Retry.
                            ServiceEventSource.Current.ServiceMessage(this.Context, $"TimeoutException in RunAsync: {te.ToString()}");
                        }
                        catch (FabricTransientException fte)
                        {
                            // transient error. Retry.
                            ServiceEventSource.Current.ServiceMessage(this.Context, $"FabricTransientException in RunAsync: {fte.ToString()}");
                        }
                        catch (FabricNotPrimaryException)
                        {
                            // not primary any more, time to quit.
                            return;
                        }
                        catch (Exception ex)
                        {
                            ServiceEventSource.Current.ServiceMessage(this.Context, ex.ToString());

                            throw;
                        }
                    }
                }
            }
            finally
            {
                if (messagingFactory != null)
                {
                    await messagingFactory.CloseAsync();
                }
            }
        }
        /// <summary>
        /// This is the main entry point for your service replica.
        /// This method executes when this replica of your service becomes primary and has write status.
        /// </summary>
        /// <param name="cancellationToken">Canceled when Service Fabric needs to shut down this service replica.</param>
        protected override async Task RunAsync(CancellationToken cancellationToken)
        {
            // Get the IoT Hub connection string from the Settings.xml config file
            // from a configuration package named "Config"
            string iotHubConnectionString =
                this.Context.CodePackageActivationContext
                .GetConfigurationPackageObject("Config")
                .Settings
                .Sections["IoTHubConfigInformation"]
                .Parameters["ConnectionString"]
                .Value;
            string iotHubProcessOnlyFutureEvents =
                this.Context.CodePackageActivationContext
                .GetConfigurationPackageObject("Config")
                .Settings
                .Sections["IoTHubConfigInformation"]
                .Parameters["ProcessOnlyFutureEvents"]
                .Value.ToLower();

            ServiceEventSource.Current.ServiceMessage(this.Context, $"RouterService - {ServiceUniqueId} - RunAsync - Starting service  - Process Only Future Events[{iotHubProcessOnlyFutureEvents}] - IoTHub Connection String[{iotHubConnectionString}]");

            // 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;

            EventHubReceiver eventHubReceiver = null;
            MessagingFactory messagingFactory = null;

            try
            {
                // HttpClient is designed as a shared object.
                // A single instance should be used throughout the lifetime of RunAsync.
                using (HttpClient httpClient = new HttpClient(new HttpServiceClientHandler()))
                {
                    int  offsetIteration = 0;
                    bool IsConnected     = false;

                    while (true)
                    {
                        cancellationToken.ThrowIfCancellationRequested();

                        if (!IsConnected)
                        {
                            // Get an EventHubReceiver and the MessagingFactory used to create it.
                            // The EventHubReceiver is used to get events from IoT Hub.
                            // The MessagingFactory is just saved for later so it can be closed before RunAsync exits.
                            Tuple <EventHubReceiver, MessagingFactory> iotHubInfo = await this.ConnectToIoTHubAsync(iotHubConnectionString, servicePartitionKey, epochDictionary, offsetDictionary, iotHubProcessOnlyFutureEvents);

                            eventHubReceiver = iotHubInfo.Item1;
                            messagingFactory = iotHubInfo.Item2;

                            IsConnected = true;
                        }

                        Uri postUrl = null;

                        try
                        {
                            // It's important to set a low wait time here in lieu of a cancellation token
                            // so that this doesn't block RunAsync from exiting when Service Fabric needs it to complete.
                            // ReceiveAsync is a long-poll operation, so the timeout should not be too low,
                            // yet not too high to block RunAsync from exiting within a few seconds.
                            using (EventData eventData = await eventHubReceiver.ReceiveAsync(TimeSpan.FromSeconds(5)))
                            {
                                if (eventData == null)
                                {
                                    ServiceEventSource.Current.ServiceMessage(this.Context, $"RouterService - {ServiceUniqueId} - RunAsync - No event data available on hub '{eventHubReceiver.Name}'");
                                    await Task.Delay(global::Iot.Common.Names.IoTHubRetryWaitIntervalsInMills);

                                    continue;
                                }
                                else
                                {
                                    ServiceEventSource.Current.ServiceMessage(this.Context, $"RouterService - {ServiceUniqueId} - RunAsync - Received event data from hub '{eventHubReceiver.Name}' - Enqueued Time[{eventData.EnqueuedTimeUtc}] - Partition '{eventData.PartitionKey}' Sequence # '{eventData.SequenceNumber}'");
                                }

                                string targetSite = (string)eventData.Properties[global::Iot.Common.Names.EventKeyFieldTargetSite];
                                string deviceId   = (string)eventData.Properties[global::Iot.Common.Names.EventKeyFieldDeviceId];

                                // This is the named service instance of the target site data service that the event should be sent to.
                                // The targetSite id is part of the named service instance name.
                                // The incoming device data stream specifie which target site the data belongs to.
                                string prefix                        = global::Iot.Common.Names.InsightApplicationNamePrefix;
                                string serviceName                   = global::Iot.Common.Names.InsightDataServiceName;
                                Uri    targetSiteServiceName         = new Uri($"{prefix}/{targetSite}/{serviceName}");
                                long   targetSiteServicePartitionKey = FnvHash.Hash(deviceId);

                                ServiceEventSource.Current.ServiceMessage(this.Context, $"RouterService - {ServiceUniqueId} - RunAsync - About to post data to Insight Data Service from device '{deviceId}' to target site '{targetSite}' - partitionKey '{targetSiteServicePartitionKey}' - Target Service Name '{targetSiteServiceName}'");

                                // The target site data service exposes an HTTP API.
                                // For incoming device events, the URL is /api/events/{deviceId}
                                // This sets up a URL and sends a POST request with the device JSON payload.
                                postUrl = new HttpServiceUriBuilder()
                                          .SetServiceName(targetSiteServiceName)
                                          .SetPartitionKey(targetSiteServicePartitionKey)
                                          .SetServicePathAndQuery($"/api/events/{deviceId}")
                                          .Build();

                                ServiceEventSource.Current.ServiceMessage(this.Context, $"RouterService - {ServiceUniqueId} - RunAsync - Ready to post data to Insight Data Service from device '{deviceId}' to taget site '{targetSite}' - partitionKey '{targetSiteServicePartitionKey}' - Target Service Name '{targetSiteServiceName}' - url '{postUrl.PathAndQuery}'");

                                // The device stream payload isn't deserialized and buffered in memory here.
                                // Instead, we just can just hook the incoming stream from Iot Hub right into the HTTP request stream.
                                using (Stream eventStream = eventData.GetBodyStream())
                                {
                                    using (StreamContent postContent = new StreamContent(eventStream))
                                    {
                                        postContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");

                                        HttpResponseMessage response = await httpClient.PostAsync(postUrl, postContent, cancellationToken);

                                        if (response.StatusCode == System.Net.HttpStatusCode.BadRequest)
                                        {
                                            // This service expects the receiving target site service to return HTTP 400 if the device message was malformed.
                                            // In this example, the message is simply logged.
                                            // Your application should handle all possible error status codes from the receiving service
                                            // and treat the message as a "poison" message.
                                            // Message processing should be allowed to continue after a poison message is detected.

                                            string responseContent = await response.Content.ReadAsStringAsync();

                                            ServiceEventSource.Current.ServiceMessage(
                                                this.Context,
                                                $"RouterService - {ServiceUniqueId} - RunAsync - Insight service '{targetSiteServiceName}' returned HTTP 400 due to a bad device message from device '{deviceId}'. Error message: '{responseContent}'");
                                        }

                                        ServiceEventSource.Current.ServiceMessage(
                                            this.Context,
                                            $"RouterService - {ServiceUniqueId} - RunAsync - Sent event data to Insight service '{targetSiteServiceName}' with partition key '{targetSiteServicePartitionKey}'. Result: {response.StatusCode.ToString()}");
                                    }
                                }

                                // 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 target site service
                                // if this service fails over after the message is sent but before the offset is saved.
                                if (++offsetIteration % OffsetInterval == 0)
                                {
                                    ServiceEventSource.Current.ServiceMessage(
                                        this.Context,
                                        $"RouterService - {ServiceUniqueId} - RunAsync - Saving offset {eventData.Offset}");

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

                                        await tx.CommitAsync();
                                    }

                                    offsetIteration = 0;
                                }
                            }
                        }
                        catch (Microsoft.ServiceBus.Messaging.ReceiverDisconnectedException rde)
                        {
                            // transient error. Retry.
                            ServiceEventSource.Current.ServiceMessage(this.Context, $"RouterService - {ServiceUniqueId} - RunAsync - Receiver Disconnected Exception in RunAsync: {rde.ToString()}");

                            IsConnected = false;
                        }
                        catch (TimeoutException te)
                        {
                            // transient error. Retry.
                            ServiceEventSource.Current.ServiceMessage(this.Context, $"RouterService - {ServiceUniqueId} - RunAsync - TimeoutException in RunAsync: {te.ToString()}");
                        }
                        catch (FabricTransientException fte)
                        {
                            // transient error. Retry.
                            ServiceEventSource.Current.ServiceMessage(this.Context, $"RouterService - {ServiceUniqueId} - RunAsync - FabricTransientException in RunAsync: {fte.ToString()}");
                        }
                        catch (FabricNotPrimaryException fnpe)
                        {
                            ServiceEventSource.Current.ServiceMessage(this.Context, $"RouterService - {ServiceUniqueId} - RunAsync - FabricNotPrimaryException Exception - Message=[{fnpe}]");

                            // not primary any more, time to quit.
                            return;
                        }
                        catch (Exception ex)
                        {
                            IsConnected = false;
                            string url = postUrl == null ? "Url undefined" : postUrl.ToString();
                            //ServiceEventSource.Current.ServiceMessage(this.Context, $"RouterService - {ServiceUniqueId} - RunAsync - General Exception Url=[{url}]- Message=[{ex}] - Inner Exception=[{ex.InnerException.Message ?? "ex.InnerException is null"}] Call Stack=[{ex.StackTrace ?? "ex.StackTrace is null"}] - Stack trace of inner exception=[{ex.InnerException.StackTrace ?? "ex.InnerException.StackTrace is null"}]");

                            ServiceEventSource.Current.ServiceMessage(this.Context, $"RouterService - {ServiceUniqueId} - RunAsync - General Exception Message[{ex.Message}] for url[{url}]");
                        }
                    }
                }
            }
            finally
            {
                if (messagingFactory != null)
                {
                    await messagingFactory.CloseAsync();
                }
            }
        }
        protected override async Task RunAsync(CancellationToken cancellationToken)
        {
            // Get the IoT Hub connection string from the Settings.xml config file
            // from a configuration package named "Config"
            string PublishDataServiceURLs =
                this.Context.CodePackageActivationContext
                .GetConfigurationPackageObject("Config")
                .Settings
                .Sections["ExtenderServiceConfigInformation"]
                .Parameters["PublishDataServiceURLs"]
                .Value.Trim('/');

            ServiceEventSource.Current.ServiceMessage(this.Context, $"ExtenderService - {ServiceUniqueId} - RunAsync - Starting service  - Data Service URLs[{PublishDataServiceURLs}]");

            DateTimeOffset currentSearchStartingTime = DateTimeOffset.UtcNow.AddHours(-1);

            if (PublishDataServiceURLs != null && PublishDataServiceURLs.Length > 0)
            {
                string[] routingparts = PublishDataServiceURLs.Split(';');
                int      currentValueForIntervalEnd = global::Iot.Common.Names.ExtenderStandardRetryWaitIntervalsInMills;

                using (HttpClient httpClient = new HttpClient(new HttpServiceClientHandler()))
                {
                    while (true)
                    {
                        cancellationToken.ThrowIfCancellationRequested();
                        string reportUniqueId = FnvHash.GetUniqueId();
                        int    messageCount   = 1;

                        while (messageCount > 0)
                        {
                            try
                            {
                                DateTimeOffset startTime           = currentSearchStartingTime;
                                long           searchIntervalStart = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - currentSearchStartingTime.ToUnixTimeMilliseconds() - 500; // this last adjusment is only to compensate for latency around the calls
                                long           searchIntervalEnd   = searchIntervalStart - currentValueForIntervalEnd;

                                if (searchIntervalEnd < 0)
                                {
                                    searchIntervalEnd          = 0;
                                    currentValueForIntervalEnd = global::Iot.Common.Names.ExtenderStandardRetryWaitIntervalsInMills;
                                }

                                DateTimeOffset endTime = DateTimeOffset.UtcNow.AddMilliseconds(searchIntervalEnd * (-1));

                                string servicePathAndQuery = $"/api/devices/history/interval/{searchIntervalStart}/{searchIntervalEnd}";

                                ServiceUriBuilder uriBuilder = new ServiceUriBuilder(routingparts[0], global::Iot.Common.Names.InsightDataServiceName);
                                Uri serviceUri = uriBuilder.Build();

                                ServiceEventSource.Current.ServiceMessage(this.Context, $"ExtenderService - {ServiceUniqueId} - RunAsync - About to call URL[{serviceUri}] to collect completed messages - Search[{servicePathAndQuery}] Time Start[{startTime}] End[{endTime}]");

                                // service may be partitioned.
                                // this will aggregate the queue lengths from each partition
                                System.Fabric.Query.ServicePartitionList partitions = await this.fabricClient.QueryManager.GetPartitionListAsync(serviceUri);

                                foreach (System.Fabric.Query.Partition partition in partitions)
                                {
                                    List <DeviceViewModelList> deviceViewModelList = new List <DeviceViewModelList>();
                                    Uri getUrl = new HttpServiceUriBuilder()
                                                 .SetServiceName(serviceUri)
                                                 .SetPartitionKey(((Int64RangePartitionInformation)partition.PartitionInformation).LowKey)
                                                 .SetServicePathAndQuery(servicePathAndQuery)
                                                 .Build();

                                    HttpResponseMessage response = await httpClient.GetAsync(getUrl, cancellationToken);

                                    if (response.StatusCode == System.Net.HttpStatusCode.OK)
                                    {
                                        JsonSerializer serializer = new JsonSerializer();
                                        using (StreamReader streamReader = new StreamReader(await response.Content.ReadAsStreamAsync()))
                                        {
                                            using (JsonTextReader jsonReader = new JsonTextReader(streamReader))
                                            {
                                                List <DeviceViewModelList> resultList = serializer.Deserialize <List <DeviceViewModelList> >(jsonReader);

                                                deviceViewModelList.AddRange(resultList);
                                            }
                                        }

                                        if (deviceViewModelList.Count > 0)
                                        {
                                            DeviceViewModelList lastItem = deviceViewModelList.ElementAt(deviceViewModelList.Count() - 1);

                                            messageCount = deviceViewModelList.Count;
                                            await ReportsHandler.PublishReportDataFor(reportUniqueId, routingparts[1], deviceViewModelList, this.Context, httpClient, cancellationToken, ServiceEventSource.Current, 1);

                                            ServiceEventSource.Current.ServiceMessage(this.Context, $"ExtenderService - {ServiceUniqueId} - RunAsync - Finished posting messages to report stream - Published total number of collected messages[{messageCount}]");
                                            currentSearchStartingTime  = endTime;
                                            currentValueForIntervalEnd = global::Iot.Common.Names.ExtenderStandardRetryWaitIntervalsInMills;
                                        }
                                        else
                                        {
                                            messageCount = 0;
                                            ServiceEventSource.Current.ServiceMessage(this.Context, $"ExtenderService - {ServiceUniqueId} - RunAsync - Could not find any messages in the interval from [{startTime}] to [{endTime}]");
                                        }
                                    }
                                    else
                                    {
                                        messageCount = 0;
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                ServiceEventSource.Current.ServiceMessage(this.Context, $"ExtenderService - {ServiceUniqueId} - RunAsync - Severe error when reading or sending messages to report stream - Exception[{ex}] - Inner Exception[{ex.InnerException}] StackTrace[{ex.StackTrace}]");
                            }
                        }

                        currentValueForIntervalEnd += global::Iot.Common.Names.ExtenderStandardRetryWaitIntervalsInMills;

                        DateTimeOffset boundaryTime = currentSearchStartingTime.AddMilliseconds(currentValueForIntervalEnd);

                        if (boundaryTime.CompareTo(DateTimeOffset.UtcNow) > 0)
                        {
                            await Task.Delay(global::Iot.Common.Names.ExtenderStandardRetryWaitIntervalsInMills);
                        }
                    }
                }
            }
            else
            {
                ServiceEventSource.Current.ServiceMessage(this.Context, $"ExtenderService - {ServiceUniqueId} - RunAsync - Starting service  - Data Service URLs[{PublishDataServiceURLs}]");
            }
        }