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)); }
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)); }
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()); }
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) })); }
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"); }
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)); }
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)); }
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); }
public void ConstructorGetScheme() { HttpServiceUriBuilder target = new HttpServiceUriBuilder("http://fabric/App/Service/#/partitionkey/any/endpoint-name/api-path"); Assert.Equal <string>("http", target.Scheme); }
public void ConstructorGetTarget(HttpServiceUriTarget expectedTarget, string url) { HttpServiceUriBuilder target = new HttpServiceUriBuilder(url); Assert.Equal <HttpServiceUriTarget>(expectedTarget, target.Target); }
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; } }
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); }
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)); }
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}]"); } }