├── src ├── Iot.Admin.WebService │ ├── .bowerrc │ ├── wwwroot │ │ ├── js │ │ │ └── site.js │ │ ├── favicon.ico │ │ ├── _references.js │ │ ├── lib │ │ │ ├── jquery │ │ │ │ ├── .bower.json │ │ │ │ └── LICENSE.txt │ │ │ ├── jquery-validation │ │ │ │ ├── .bower.json │ │ │ │ └── LICENSE.md │ │ │ └── jquery-validation-unobtrusive │ │ │ │ ├── .bower.json │ │ │ │ └── jquery.validate.unobtrusive.min.js │ │ └── css │ │ │ └── site.css │ ├── Views │ │ ├── _ViewStart.cshtml │ │ ├── _ViewImports.cshtml │ │ └── Shared │ │ │ ├── _Layout.cshtml │ │ │ └── Error.cshtml │ ├── bower.json │ ├── appsettings.json │ ├── PackageRoot │ │ ├── Config │ │ │ └── Settings.xml │ │ └── ServiceManifest.xml │ ├── web.config │ ├── Controllers │ │ ├── HomeController.cs │ │ ├── IngestionController.cs │ │ └── TenantsController.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Models │ │ ├── IngestionApplicationParams.cs │ │ └── TenantApplicationParams.cs │ ├── Program.cs │ ├── ViewModels │ │ └── ApplicationViewModel.cs │ ├── LocalServer.cs │ ├── Iot.Admin.WebService.csproj │ ├── WebService.cs │ └── Startup.cs ├── Iot.Tenant.WebService │ ├── .bowerrc │ ├── wwwroot │ │ ├── js │ │ │ └── site.js │ │ ├── favicon.ico │ │ ├── _references.js │ │ ├── lib │ │ │ ├── jquery │ │ │ │ ├── .bower.json │ │ │ │ └── LICENSE.txt │ │ │ ├── jquery-validation │ │ │ │ ├── .bower.json │ │ │ │ └── LICENSE.md │ │ │ └── jquery-validation-unobtrusive │ │ │ │ ├── .bower.json │ │ │ │ └── jquery.validate.unobtrusive.min.js │ │ └── css │ │ │ └── site.css │ ├── Views │ │ ├── _ViewStart.cshtml │ │ ├── _ViewImports.cshtml │ │ ├── Shared │ │ │ ├── _Layout.cshtml │ │ │ └── Error.cshtml │ │ └── Home │ │ │ └── Index.cshtml │ ├── bower.json │ ├── appsettings.json │ ├── PackageRoot │ │ ├── Config │ │ │ └── Settings.xml │ │ └── ServiceManifest.xml │ ├── web.config │ ├── ViewModels │ │ └── DeviceViewModel.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Program.cs │ ├── Controllers │ │ ├── HomeController.cs │ │ └── DevicesController.cs │ ├── Iot.Tenant.WebService.csproj │ ├── Startup.cs │ └── WebService.cs ├── Iot.Admin.Application │ ├── packages.config │ ├── PublishProfiles │ │ ├── Local.1Node.xml │ │ └── Local.5Node.xml │ ├── ApplicationParameters │ │ ├── Cloud.xml │ │ ├── Local.1Node.xml │ │ └── Local.5Node.xml │ ├── app.config │ ├── ApplicationPackageRoot │ │ └── ApplicationManifest.xml │ └── Iot.Admin.Application.sfproj ├── Iot.Tenant.Application │ ├── packages.config │ ├── PublishProfiles │ │ ├── Local.1Node.xml │ │ └── Local.5Node.xml │ ├── app.config │ ├── ApplicationPackageRoot │ │ └── ApplicationManifest.xml │ └── Iot.Tenant.Application.sfproj ├── Iot.Ingestion.Application │ ├── packages.config │ ├── PublishProfiles │ │ ├── Local.1Node.xml │ │ └── Local.5Node.xml │ ├── app.config │ ├── ApplicationPackageRoot │ │ └── ApplicationManifest.xml │ └── Iot.Ingestion.Application.sfproj ├── Iot.Tenant.DataService │ ├── appsettings.json │ ├── AssemblyInfo.cs │ ├── PackageRoot │ │ ├── Config │ │ │ └── Settings.xml │ │ └── ServiceManifest.xml │ ├── web.config │ ├── Models │ │ ├── DeviceEvent.cs │ │ └── DeviceEventSeries.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Program.cs │ ├── Startup.cs │ ├── Iot.Tenant.DataService.csproj │ ├── Controllers │ │ ├── DevicesController.cs │ │ └── EventsController.cs │ └── DataService.cs ├── Iot.Common │ ├── app.config │ ├── HttpServiceUriTarget.cs │ ├── FnvHash.cs │ ├── Names.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── ServiceUriBuilder.cs │ ├── packages.config │ └── HttpServiceUriBuilder.cs ├── Iot.Mocks │ ├── app.config │ ├── MockApplicationLifetime.cs │ ├── MockTransaction.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── MockAsyncEnumerable.cs │ ├── MockReliableQueue.cs │ ├── packages.config │ └── MockCodePackageActivationContext.cs ├── Deploy │ ├── Local.1Node.xml │ ├── Local.5Node.xml │ └── Cloud.xml ├── Iot.Ingestion.RouterService │ ├── PackageRoot │ │ ├── Config │ │ │ └── Settings.xml │ │ └── ServiceManifest.xml │ ├── packages.config │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── App.config ├── Iot.Tenant.DataService.Tests │ ├── Iot.Tenant.DataService.Tests.csproj │ └── DevicesControllerTests.cs └── Iot.DeviceEmulator │ ├── Properties │ └── AssemblyInfo.cs │ ├── App.config │ └── packages.config ├── docs ├── conceptual.png └── overview.png ├── CONTRIBUTING.md ├── LICENSE └── .gitignore /src/Iot.Admin.WebService/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "wwwroot/lib" 3 | } 4 | -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/wwwroot/js/site.js: -------------------------------------------------------------------------------- 1 | // Write your Javascript code. 2 | -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "wwwroot/lib" 3 | } 4 | -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/wwwroot/js/site.js: -------------------------------------------------------------------------------- 1 | // Write your Javascript code. 2 | -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 2 | -------------------------------------------------------------------------------- /docs/conceptual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure-Samples/service-fabric-dotnet-iot/HEAD/docs/conceptual.png -------------------------------------------------------------------------------- /docs/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure-Samples/service-fabric-dotnet-iot/HEAD/docs/overview.png -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 2 | -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure-Samples/service-fabric-dotnet-iot/HEAD/src/Iot.Admin.WebService/wwwroot/favicon.ico -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure-Samples/service-fabric-dotnet-iot/HEAD/src/Iot.Tenant.WebService/wwwroot/favicon.ico -------------------------------------------------------------------------------- /src/Iot.Admin.Application/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Iot.Tenant.Application/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Iot.Ingestion.Application/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "asp.net", 3 | "private": true, 4 | "dependencies": { 5 | "jquery": "2.2.0", 6 | "jquery-validation": "1.14.0", 7 | "jquery-validation-unobtrusive": "3.2.6" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "asp.net", 3 | "private": true, 4 | "dependencies": { 5 | "jquery": "2.2.0", 6 | "jquery-validation": "1.14.0", 7 | "jquery-validation-unobtrusive": "3.2.6" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "IncludeScopes": false, 4 | "LogLevel": { 5 | "Default": "Debug", 6 | "System": "Information", 7 | "Microsoft": "Information" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "IncludeScopes": false, 4 | "LogLevel": { 5 | "Default": "Debug", 6 | "System": "Information", 7 | "Microsoft": "Information" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Iot.Tenant.DataService/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "IncludeScopes": false, 4 | "LogLevel": { 5 | "Default": "Debug", 6 | "System": "Information", 7 | "Microsoft": "Information" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Iot.Admin.Application/PublishProfiles/Local.1Node.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Iot.Admin.Application/PublishProfiles/Local.5Node.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Iot.Ingestion.Application/PublishProfiles/Local.1Node.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Iot.Ingestion.Application/PublishProfiles/Local.5Node.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Iot.Tenant.Application/PublishProfiles/Local.1Node.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Iot.Tenant.Application/PublishProfiles/Local.5Node.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/wwwroot/_references.js: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | /// 5 | /// 6 | -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/wwwroot/_references.js: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | /// 5 | /// 6 | -------------------------------------------------------------------------------- /src/Iot.Admin.Application/ApplicationParameters/Cloud.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/Iot.Admin.Application/ApplicationParameters/Local.1Node.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/Iot.Admin.Application/ApplicationParameters/Local.5Node.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/Iot.Tenant.DataService/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | using System.Runtime.CompilerServices; 7 | 8 | [assembly: InternalsVisibleTo("Iot.Tenant.DataService.Tests")] -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/PackageRoot/Config/Settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /src/Iot.Tenant.DataService/PackageRoot/Config/Settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/PackageRoot/Config/Settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /src/Iot.Admin.Application/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/Iot.Common/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/Iot.Mocks/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/Iot.Tenant.Application/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Iot.Tenant.DataService/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Deploy/Local.1Node.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/Deploy/Local.5Node.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | @ViewData["Title"] - Iot.Admin.WebService 7 | 8 | 9 | 10 |
11 |
12 | @RenderBody() 13 |
14 |
15 | 16 | 17 | @RenderSection("scripts", required: false) 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/wwwroot/lib/jquery/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery", 3 | "main": "dist/jquery.js", 4 | "license": "MIT", 5 | "ignore": [ 6 | "package.json" 7 | ], 8 | "keywords": [ 9 | "jquery", 10 | "javascript", 11 | "browser", 12 | "library" 13 | ], 14 | "homepage": "https://github.com/jquery/jquery-dist", 15 | "version": "2.2.0", 16 | "_release": "2.2.0", 17 | "_resolution": { 18 | "type": "version", 19 | "tag": "2.2.0", 20 | "commit": "6fc01e29bdad0964f62ef56d01297039cdcadbe5" 21 | }, 22 | "_source": "git://github.com/jquery/jquery-dist.git", 23 | "_target": "2.2.0", 24 | "_originalSource": "jquery" 25 | } -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/wwwroot/lib/jquery/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery", 3 | "main": "dist/jquery.js", 4 | "license": "MIT", 5 | "ignore": [ 6 | "package.json" 7 | ], 8 | "keywords": [ 9 | "jquery", 10 | "javascript", 11 | "browser", 12 | "library" 13 | ], 14 | "homepage": "https://github.com/jquery/jquery-dist", 15 | "version": "2.2.0", 16 | "_release": "2.2.0", 17 | "_resolution": { 18 | "type": "version", 19 | "tag": "2.2.0", 20 | "commit": "6fc01e29bdad0964f62ef56d01297039cdcadbe5" 21 | }, 22 | "_source": "git://github.com/jquery/jquery-dist.git", 23 | "_target": "2.2.0", 24 | "_originalSource": "jquery" 25 | } -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | @ViewData["Tenant"] Dashboard 7 | 8 | 9 | 10 |
11 |
12 |

@ViewData["Tenant"]

Dashboard 13 |
14 | @RenderBody() 15 |
16 |
17 | 18 | 19 | @RenderSection("scripts", required: false) 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/Iot.Ingestion.RouterService/PackageRoot/Config/Settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 |
7 | 8 |
9 | 10 |
11 | 12 |
13 | 14 | -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Admin.WebService.Controllers 7 | { 8 | using Microsoft.AspNetCore.Mvc; 9 | 10 | public class HomeController : Controller 11 | { 12 | public IActionResult Index() 13 | { 14 | return this.View(); 15 | } 16 | 17 | public IActionResult Error() 18 | { 19 | return this.View(); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:5000/", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "Iot.Admin.WebService": { 19 | "commandName": "Project", 20 | "launchUrl": "http://localhost:5001", 21 | "environmentVariables": { 22 | "ASPNETCORE_ENVIRONMENT": "Development" 23 | } 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/Iot.Tenant.DataService/Models/DeviceEvent.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Tenant.DataService.Models 7 | { 8 | using System; 9 | using System.Runtime.Serialization; 10 | 11 | [DataContract] 12 | public class DeviceEvent 13 | { 14 | public DeviceEvent(DateTimeOffset timestamp) 15 | { 16 | this.Timestamp = timestamp; 17 | } 18 | 19 | [DataMember] 20 | public DateTimeOffset Timestamp { get; private set; } 21 | } 22 | } -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/ViewModels/DeviceViewModel.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Tenant.WebService.ViewModels 7 | { 8 | using System; 9 | 10 | public class DeviceViewModel 11 | { 12 | public DeviceViewModel(string id, DateTimeOffset timestamp) 13 | { 14 | this.Id = id; 15 | this.Timestamp = timestamp; 16 | } 17 | 18 | public string Id { get; private set; } 19 | 20 | public DateTimeOffset Timestamp { get; private set; } 21 | } 22 | } -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Error"; 3 | } 4 | 5 |

Error.

6 |

An error occurred while processing your request.

7 | 8 |

Development Mode

9 |

10 | Swapping to Development environment will display more detailed information about the error that occurred. 11 |

12 |

13 | Development environment should not be enabled in deployed applications, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the ASPNETCORE_ENVIRONMENT environment variable to Development, and restarting the application. 14 |

15 | -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": false, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:27802/", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "Iot.Tenant.WebService": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "launchUrl": "http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Error"; 3 | } 4 | 5 |

Error.

6 |

An error occurred while processing your request.

7 | 8 |

Development Mode

9 |

10 | Swapping to Development environment will display more detailed information about the error that occurred. 11 |

12 |

13 | Development environment should not be enabled in deployed applications, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the ASPNETCORE_ENVIRONMENT environment variable to Development, and restarting the application. 14 |

15 | -------------------------------------------------------------------------------- /src/Iot.Tenant.DataService/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:27825/", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "launchUrl": "api/values", 15 | "environmentVariables": { 16 | "ASPNETCORE_ENVIRONMENT": "Development" 17 | } 18 | }, 19 | "Iot.Tenant.DataService": { 20 | "commandName": "Project", 21 | "launchBrowser": true, 22 | "launchUrl": "http://localhost:5000/api/values", 23 | "environmentVariables": { 24 | "ASPNETCORE_ENVIRONMENT": "Development" 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/Models/IngestionApplicationParams.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Admin.WebService.Models 7 | { 8 | public class IngestionApplicationParams 9 | { 10 | public IngestionApplicationParams(string iotHubConnectionString, int partitionCount, string version) 11 | { 12 | this.IotHubConnectionString = iotHubConnectionString; 13 | this.Version = version; 14 | } 15 | 16 | public string IotHubConnectionString { get; set; } 17 | 18 | public string Version { get; set; } 19 | } 20 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Azure samples 2 | 3 | Thank you for your interest in contributing to Azure samples! 4 | 5 | ## Ways to contribute 6 | 7 | You can contribute to [Azure samples](https://azure.microsoft.com/documentation/samples/) in a few different ways: 8 | 9 | - Submit feedback on [this sample page](https://azure.microsoft.com/documentation/samples/service-fabric-dotnet-iot/) whether it was helpful or not. 10 | - Submit issues through [issue tracker](https://github.com/Azure-Samples/service-fabric-dotnet-iot/issues) on GitHub. We are actively monitoring the issues and improving our samples. 11 | - If you wish to make code changes to samples, or contribute something new, please follow the [GitHub Forks / Pull requests model](https://help.github.com/articles/fork-a-repo/): Fork the sample repo, make the change and propose it back by submitting a pull request. -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/Program.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Tenant.WebService 7 | { 8 | using System.Threading; 9 | using Microsoft.ServiceFabric.Services.Runtime; 10 | 11 | public class Program 12 | { 13 | // Entry point for the application. 14 | public static void Main(string[] args) 15 | { 16 | ServiceRuntime.RegisterServiceAsync( 17 | "WebServiceType", 18 | context => 19 | new WebService(context)).GetAwaiter().GetResult(); 20 | 21 | Thread.Sleep(Timeout.Infinite); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/Iot.Tenant.DataService/Program.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Tenant.DataService 7 | { 8 | using System.Threading; 9 | using Microsoft.ServiceFabric.Services.Runtime; 10 | 11 | public class Program 12 | { 13 | // Entry point for the application. 14 | public static void Main(string[] args) 15 | { 16 | ServiceRuntime.RegisterServiceAsync( 17 | "DataServiceType", 18 | context => 19 | new DataService(context)).GetAwaiter().GetResult(); 20 | 21 | Thread.Sleep(Timeout.Infinite); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/Models/TenantApplicationParams.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Admin.WebService.Models 7 | { 8 | public class TenantApplicationParams 9 | { 10 | public TenantApplicationParams(int dataPartitionCount, int webInstanceCount, string version) 11 | { 12 | this.DataPartitionCount = dataPartitionCount; 13 | this.WebInstanceCount = webInstanceCount; 14 | this.Version = version; 15 | } 16 | 17 | public int DataPartitionCount { get; set; } 18 | 19 | public int WebInstanceCount { get; set; } 20 | 21 | public string Version { get; set; } 22 | } 23 | } -------------------------------------------------------------------------------- /src/Iot.Tenant.DataService/Models/DeviceEventSeries.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Tenant.DataService.Models 7 | { 8 | using System.Collections.Generic; 9 | using System.Runtime.Serialization; 10 | 11 | [DataContract] 12 | internal class DeviceEventSeries 13 | { 14 | public DeviceEventSeries(string deviceId, IEnumerable events) 15 | { 16 | this.DeviceId = deviceId; 17 | this.Events = events; 18 | } 19 | 20 | [DataMember] 21 | public string DeviceId { get; private set; } 22 | 23 | [DataMember] 24 | public IEnumerable Events { get; private set; } 25 | } 26 | } -------------------------------------------------------------------------------- /src/Iot.Ingestion.Application/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Iot.Tenant.Application/ApplicationPackageRoot/ApplicationManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Iot.Common/HttpServiceUriTarget.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Common 7 | { 8 | public enum HttpServiceUriTarget 9 | { 10 | /// 11 | /// Primary for stateful, Any for stateless. 12 | /// 13 | Default, 14 | 15 | /// 16 | /// Selects the primary replica of a stateful service. 17 | /// 18 | Primary, 19 | 20 | /// 21 | /// Selects a random secondary replica of a stateful service. 22 | /// 23 | Secondary, 24 | 25 | /// 26 | /// Selects a random replica of a stateful service or a random instance of a stateless service. 27 | /// 28 | Any 29 | } 30 | } -------------------------------------------------------------------------------- /src/Iot.Common/FnvHash.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Common 7 | { 8 | using System.Text; 9 | 10 | public sealed class FnvHash 11 | { 12 | private const ulong FnvPrime = 1099511628211; 13 | private const ulong FnvOffsetBasis = 14695981039346656037; 14 | 15 | public static long Hash(string value) 16 | { 17 | return Hash(Encoding.UTF8.GetBytes(value)); 18 | } 19 | 20 | public static long Hash(byte[] value) 21 | { 22 | ulong hash = FnvOffsetBasis; 23 | for (int i = 0; i < value.Length; ++i) 24 | { 25 | hash ^= value[i]; 26 | hash *= FnvPrime; 27 | } 28 | 29 | return (long) hash; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/Iot.Mocks/MockApplicationLifetime.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Threading; 8 | 9 | namespace Iot.Mocks 10 | { 11 | public class MockApplicationLifetime : IApplicationLifetime 12 | { 13 | private readonly CancellationTokenSource source; 14 | 15 | public MockApplicationLifetime() 16 | { 17 | this.source = new CancellationTokenSource(); 18 | this.ApplicationStopping = this.source.Token; 19 | this.ApplicationStopped = this.source.Token; 20 | } 21 | 22 | public CancellationToken ApplicationStarted { get; private set; } 23 | 24 | public CancellationToken ApplicationStopped { get; private set; } 25 | 26 | public CancellationToken ApplicationStopping { get; private set; } 27 | 28 | public void StopApplication() 29 | { 30 | this.source.Cancel(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/Program.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Admin.WebService 7 | { 8 | using System.Threading; 9 | using Microsoft.ServiceFabric.Services.Runtime; 10 | 11 | public class Program 12 | { 13 | // Entry point for the application. 14 | public static void Main(string[] args) 15 | { 16 | #if LOCALSERVER 17 | 18 | using (LocalServer listener = new LocalServer()) 19 | { 20 | listener.Open(); 21 | } 22 | 23 | #else 24 | ServiceRuntime.RegisterServiceAsync( 25 | "WebServiceType", 26 | context => 27 | new WebService(context)).GetAwaiter().GetResult(); 28 | 29 | Thread.Sleep(Timeout.Infinite); 30 | #endif 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/wwwroot/lib/jquery-validation/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-validation", 3 | "homepage": "http://jqueryvalidation.org/", 4 | "repository": { 5 | "type": "git", 6 | "url": "git://github.com/jzaefferer/jquery-validation.git" 7 | }, 8 | "authors": [ 9 | "Jörn Zaefferer " 10 | ], 11 | "description": "Form validation made easy", 12 | "main": "dist/jquery.validate.js", 13 | "keywords": [ 14 | "forms", 15 | "validation", 16 | "validate" 17 | ], 18 | "license": "MIT", 19 | "ignore": [ 20 | "**/.*", 21 | "node_modules", 22 | "bower_components", 23 | "test", 24 | "demo", 25 | "lib" 26 | ], 27 | "dependencies": { 28 | "jquery": ">= 1.7.2" 29 | }, 30 | "version": "1.14.0", 31 | "_release": "1.14.0", 32 | "_resolution": { 33 | "type": "version", 34 | "tag": "1.14.0", 35 | "commit": "c1343fb9823392aa9acbe1c3ffd337b8c92fed48" 36 | }, 37 | "_source": "git://github.com/jzaefferer/jquery-validation.git", 38 | "_target": ">=1.8", 39 | "_originalSource": "jquery-validation" 40 | } -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/wwwroot/lib/jquery-validation/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-validation", 3 | "homepage": "http://jqueryvalidation.org/", 4 | "repository": { 5 | "type": "git", 6 | "url": "git://github.com/jzaefferer/jquery-validation.git" 7 | }, 8 | "authors": [ 9 | "Jörn Zaefferer " 10 | ], 11 | "description": "Form validation made easy", 12 | "main": "dist/jquery.validate.js", 13 | "keywords": [ 14 | "forms", 15 | "validation", 16 | "validate" 17 | ], 18 | "license": "MIT", 19 | "ignore": [ 20 | "**/.*", 21 | "node_modules", 22 | "bower_components", 23 | "test", 24 | "demo", 25 | "lib" 26 | ], 27 | "dependencies": { 28 | "jquery": ">= 1.7.2" 29 | }, 30 | "version": "1.14.0", 31 | "_release": "1.14.0", 32 | "_resolution": { 33 | "type": "version", 34 | "tag": "1.14.0", 35 | "commit": "c1343fb9823392aa9acbe1c3ffd337b8c92fed48" 36 | }, 37 | "_source": "git://github.com/jzaefferer/jquery-validation.git", 38 | "_target": ">=1.8", 39 | "_originalSource": "jquery-validation" 40 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Microsoft Corporation 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/ViewModels/ApplicationViewModel.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Admin.WebService.ViewModels 7 | { 8 | using System.Fabric.Description; 9 | 10 | public class ApplicationViewModel 11 | { 12 | public ApplicationViewModel(string name, string status, string typeVersion, ApplicationParameterList parameters) 13 | { 14 | this.ApplicationName = name; 15 | this.ApplicationStatus = status; 16 | this.ApplicationTypeVersion = typeVersion; 17 | this.ApplicationParameters = parameters; 18 | } 19 | 20 | public string ApplicationName { get; private set; } 21 | 22 | public string ApplicationStatus { get; private set; } 23 | 24 | public string ApplicationTypeVersion { get; private set; } 25 | 26 | public ApplicationParameterList ApplicationParameters { get; private set; } 27 | } 28 | } -------------------------------------------------------------------------------- /src/Iot.Mocks/MockTransaction.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Mocks 7 | { 8 | using System; 9 | using System.Threading.Tasks; 10 | using Microsoft.ServiceFabric.Data; 11 | 12 | public class MockTransaction : ITransaction 13 | { 14 | public Task CommitAsync() 15 | { 16 | return Task.FromResult(true); 17 | } 18 | 19 | public void Abort() 20 | { 21 | } 22 | 23 | public long TransactionId 24 | { 25 | get { return 0L; } 26 | } 27 | 28 | public long CommitSequenceNumber 29 | { 30 | get { throw new NotImplementedException(); } 31 | } 32 | 33 | public void Dispose() 34 | { 35 | } 36 | 37 | public Task GetVisibilitySequenceNumberAsync() 38 | { 39 | return Task.FromResult(0L); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /src/Iot.Common/Names.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Common 7 | { 8 | public static class Names 9 | { 10 | public const string IngestionApplicationPrefix = "fabric:/Iot.Ingestion"; 11 | public const string IngestionApplicationTypeName = "IotIngestionApplicationType"; 12 | public const string IngestionRouterServiceName = "RouterService"; 13 | public const string IngestionRouterServiceTypeName = "RouterServiceType"; 14 | 15 | public const string TenantApplicationNamePrefix = "fabric:/Iot.Tenant"; 16 | public const string TenantApplicationTypeName = "IotTenantApplicationType"; 17 | public const string TenantDataServiceName = "DataService"; 18 | public const string TenantDataServiceTypeName = "DataServiceType"; 19 | public const string TenantWebServiceName = "WebService"; 20 | public const string TenantWebServiceTypeName = "WebServiceType"; 21 | } 22 | } -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/wwwroot/lib/jquery-validation/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright Jörn Zaefferer 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/wwwroot/lib/jquery-validation/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright Jörn Zaefferer 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /src/Iot.Ingestion.Application/ApplicationPackageRoot/ApplicationManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 |
17 |
18 |
19 |
20 |
21 |
-------------------------------------------------------------------------------- /src/Iot.Admin.WebService/wwwroot/lib/jquery-validation-unobtrusive/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-validation-unobtrusive", 3 | "version": "3.2.6", 4 | "homepage": "https://github.com/aspnet/jquery-validation-unobtrusive", 5 | "description": "Add-on to jQuery Validation to enable unobtrusive validation options in data-* attributes.", 6 | "main": [ 7 | "jquery.validate.unobtrusive.js" 8 | ], 9 | "ignore": [ 10 | "**/.*", 11 | "*.json", 12 | "*.md", 13 | "*.txt", 14 | "gulpfile.js" 15 | ], 16 | "keywords": [ 17 | "jquery", 18 | "asp.net", 19 | "mvc", 20 | "validation", 21 | "unobtrusive" 22 | ], 23 | "authors": [ 24 | "Microsoft" 25 | ], 26 | "license": "http://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm", 27 | "repository": { 28 | "type": "git", 29 | "url": "git://github.com/aspnet/jquery-validation-unobtrusive.git" 30 | }, 31 | "dependencies": { 32 | "jquery-validation": ">=1.8", 33 | "jquery": ">=1.8" 34 | }, 35 | "_release": "3.2.6", 36 | "_resolution": { 37 | "type": "version", 38 | "tag": "v3.2.6", 39 | "commit": "13386cd1b5947d8a5d23a12b531ce3960be1eba7" 40 | }, 41 | "_source": "git://github.com/aspnet/jquery-validation-unobtrusive.git", 42 | "_target": "3.2.6", 43 | "_originalSource": "jquery-validation-unobtrusive" 44 | } -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/wwwroot/lib/jquery-validation-unobtrusive/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-validation-unobtrusive", 3 | "version": "3.2.6", 4 | "homepage": "https://github.com/aspnet/jquery-validation-unobtrusive", 5 | "description": "Add-on to jQuery Validation to enable unobtrusive validation options in data-* attributes.", 6 | "main": [ 7 | "jquery.validate.unobtrusive.js" 8 | ], 9 | "ignore": [ 10 | "**/.*", 11 | "*.json", 12 | "*.md", 13 | "*.txt", 14 | "gulpfile.js" 15 | ], 16 | "keywords": [ 17 | "jquery", 18 | "asp.net", 19 | "mvc", 20 | "validation", 21 | "unobtrusive" 22 | ], 23 | "authors": [ 24 | "Microsoft" 25 | ], 26 | "license": "http://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm", 27 | "repository": { 28 | "type": "git", 29 | "url": "git://github.com/aspnet/jquery-validation-unobtrusive.git" 30 | }, 31 | "dependencies": { 32 | "jquery-validation": ">=1.8", 33 | "jquery": ">=1.8" 34 | }, 35 | "_release": "3.2.6", 36 | "_resolution": { 37 | "type": "version", 38 | "tag": "v3.2.6", 39 | "commit": "13386cd1b5947d8a5d23a12b531ce3960be1eba7" 40 | }, 41 | "_source": "git://github.com/aspnet/jquery-validation-unobtrusive.git", 42 | "_target": "3.2.6", 43 | "_originalSource": "jquery-validation-unobtrusive" 44 | } -------------------------------------------------------------------------------- /src/Iot.Tenant.DataService.Tests/Iot.Tenant.DataService.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net452 5 | x64 6 | Iot.Tenant.DataService.Tests 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Tenant.WebService.Controllers 7 | { 8 | using System.Fabric; 9 | using System.Linq; 10 | using Microsoft.AspNetCore.Mvc; 11 | 12 | public class HomeController : Controller 13 | { 14 | private readonly StatelessServiceContext context; 15 | 16 | public HomeController(StatelessServiceContext context) 17 | { 18 | this.context = context; 19 | } 20 | 21 | public IActionResult Index() 22 | { 23 | this.ViewData["Tenant"] = this.context.ServiceName.AbsolutePath.Split('/').Last(); 24 | return this.View(); 25 | } 26 | 27 | public IActionResult About() 28 | { 29 | this.ViewData["Message"] = "Your application description page."; 30 | 31 | return this.View(); 32 | } 33 | 34 | public IActionResult Contact() 35 | { 36 | this.ViewData["Message"] = "Your contact page."; 37 | 38 | return this.View(); 39 | } 40 | 41 | public IActionResult Error() 42 | { 43 | return this.View(); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /src/Iot.Ingestion.RouterService/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Iot.Admin.Application/ApplicationPackageRoot/ApplicationManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/LocalServer.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Admin.WebService 7 | { 8 | using System; 9 | using System.Fabric; 10 | using System.IO; 11 | using System.Threading; 12 | using Microsoft.AspNetCore.Hosting; 13 | using Microsoft.Extensions.DependencyInjection; 14 | 15 | public class LocalServer : IDisposable 16 | { 17 | private IWebHost webHost; 18 | 19 | public void Dispose() 20 | { 21 | this.webHost?.Dispose(); 22 | } 23 | 24 | public void Open() 25 | { 26 | string serverUrl = "http://localhost:5001/iot"; 27 | 28 | CancellationTokenSource webApiCancellationSource = new CancellationTokenSource(); 29 | FabricClient fabricClient = new FabricClient(); 30 | 31 | this.webHost = new WebHostBuilder().UseKestrel() 32 | .ConfigureServices( 33 | services => services 34 | .AddSingleton(fabricClient) 35 | .AddSingleton(webApiCancellationSource)) 36 | .UseContentRoot(Directory.GetCurrentDirectory()) 37 | .UseStartup() 38 | .UseUrls(serverUrl) 39 | .Build(); 40 | 41 | this.webHost.Run(); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/PackageRoot/ServiceManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Iot.Admin.WebService.exe 18 | CodePackage 19 | 20 | 21 | 22 | 23 | 25 | 26 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/PackageRoot/ServiceManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Iot.Tenant.WebService.exe 18 | CodePackage 19 | 20 | 21 | 22 | 23 | 25 | 26 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/Iot.Tenant.DataService/PackageRoot/ServiceManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Iot.Tenant.DataService.exe 18 | CodePackage 19 | 20 | 21 | 22 | 23 | 25 | 26 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/Deploy/Cloud.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/wwwroot/lib/jquery/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright jQuery Foundation and other contributors, https://jquery.org/ 2 | 3 | This software consists of voluntary contributions made by many 4 | individuals. For exact contribution history, see the revision history 5 | available at https://github.com/jquery/jquery 6 | 7 | The following license applies to all parts of this software except as 8 | documented below: 9 | 10 | ==== 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining 13 | a copy of this software and associated documentation files (the 14 | "Software"), to deal in the Software without restriction, including 15 | without limitation the rights to use, copy, modify, merge, publish, 16 | distribute, sublicense, and/or sell copies of the Software, and to 17 | permit persons to whom the Software is furnished to do so, subject to 18 | the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be 21 | included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | ==== 32 | 33 | All files located in the node_modules and external directories are 34 | externally maintained libraries used by this software which have their 35 | own licenses; we recommend you read them, as their terms may differ from 36 | the terms above. 37 | -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/wwwroot/lib/jquery/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright jQuery Foundation and other contributors, https://jquery.org/ 2 | 3 | This software consists of voluntary contributions made by many 4 | individuals. For exact contribution history, see the revision history 5 | available at https://github.com/jquery/jquery 6 | 7 | The following license applies to all parts of this software except as 8 | documented below: 9 | 10 | ==== 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining 13 | a copy of this software and associated documentation files (the 14 | "Software"), to deal in the Software without restriction, including 15 | without limitation the rights to use, copy, modify, merge, publish, 16 | distribute, sublicense, and/or sell copies of the Software, and to 17 | permit persons to whom the Software is furnished to do so, subject to 18 | the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be 21 | included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | ==== 32 | 33 | All files located in the node_modules and external directories are 34 | externally maintained libraries used by this software which have their 35 | own licenses; we recommend you read them, as their terms may differ from 36 | the terms above. 37 | -------------------------------------------------------------------------------- /src/Iot.Common/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | using System.Reflection; 7 | using System.Runtime.InteropServices; 8 | 9 | // General Information about an assembly is controlled through the following 10 | // set of attributes. Change these attribute values to modify the information 11 | // associated with an assembly. 12 | 13 | [assembly: AssemblyTitle("Iot.Common")] 14 | [assembly: AssemblyDescription("")] 15 | [assembly: AssemblyConfiguration("")] 16 | [assembly: AssemblyCompany("")] 17 | [assembly: AssemblyProduct("Iot.Common")] 18 | [assembly: AssemblyCopyright("Copyright © 2016")] 19 | [assembly: AssemblyTrademark("")] 20 | [assembly: AssemblyCulture("")] 21 | 22 | // Setting ComVisible to false makes the types in this assembly not visible 23 | // to COM components. If you need to access a type in this assembly from 24 | // COM, set the ComVisible attribute to true on that type. 25 | 26 | [assembly: ComVisible(false)] 27 | 28 | // The following GUID is for the ID of the typelib if this project is exposed to COM 29 | 30 | [assembly: Guid("35072b44-bc38-4d61-b96c-af2bcffafb41")] 31 | 32 | // Version information for an assembly consists of the following four values: 33 | // 34 | // Major Version 35 | // Minor Version 36 | // Build Number 37 | // Revision 38 | // 39 | // You can specify all the values or you can default the Build and Revision Numbers 40 | // by using the '*' as shown below: 41 | // [assembly: AssemblyVersion("1.0.*")] 42 | 43 | [assembly: AssemblyVersion("1.0.0.0")] 44 | [assembly: AssemblyFileVersion("1.0.0.0")] -------------------------------------------------------------------------------- /src/Iot.Mocks/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | using System.Reflection; 7 | using System.Runtime.InteropServices; 8 | 9 | // General Information about an assembly is controlled through the following 10 | // set of attributes. Change these attribute values to modify the information 11 | // associated with an assembly. 12 | 13 | [assembly: AssemblyTitle("Iot.Mocks")] 14 | [assembly: AssemblyDescription("")] 15 | [assembly: AssemblyConfiguration("")] 16 | [assembly: AssemblyCompany("")] 17 | [assembly: AssemblyProduct("Iot.Mocks")] 18 | [assembly: AssemblyCopyright("Copyright © 2016")] 19 | [assembly: AssemblyTrademark("")] 20 | [assembly: AssemblyCulture("")] 21 | 22 | // Setting ComVisible to false makes the types in this assembly not visible 23 | // to COM components. If you need to access a type in this assembly from 24 | // COM, set the ComVisible attribute to true on that type. 25 | 26 | [assembly: ComVisible(false)] 27 | 28 | // The following GUID is for the ID of the typelib if this project is exposed to COM 29 | 30 | [assembly: Guid("e05f8f27-a728-4c38-baf9-d78228099fce")] 31 | 32 | // Version information for an assembly consists of the following four values: 33 | // 34 | // Major Version 35 | // Minor Version 36 | // Build Number 37 | // Revision 38 | // 39 | // You can specify all the values or you can default the Build and Revision Numbers 40 | // by using the '*' as shown below: 41 | // [assembly: AssemblyVersion("1.0.*")] 42 | 43 | [assembly: AssemblyVersion("1.0.0.0")] 44 | [assembly: AssemblyFileVersion("1.0.0.0")] -------------------------------------------------------------------------------- /src/Iot.Ingestion.RouterService/Program.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Ingestion.RouterService 7 | { 8 | using System; 9 | using System.Diagnostics; 10 | using System.Threading; 11 | using Microsoft.ServiceFabric.Services.Runtime; 12 | 13 | internal static class Program 14 | { 15 | /// 16 | /// This is the entry point of the service host process. 17 | /// 18 | private static void Main() 19 | { 20 | try 21 | { 22 | // The ServiceManifest.XML file defines one or more service type names. 23 | // Registering a service maps a service type name to a .NET type. 24 | // When Service Fabric creates an instance of this service type, 25 | // an instance of the class is created in this host process. 26 | 27 | ServiceRuntime.RegisterServiceAsync( 28 | "RouterServiceType", 29 | context => new RouterService(context)).GetAwaiter().GetResult(); 30 | 31 | ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(RouterService).Name); 32 | 33 | // Prevents this host process from terminating so services keep running. 34 | Thread.Sleep(Timeout.Infinite); 35 | } 36 | catch (Exception e) 37 | { 38 | ServiceEventSource.Current.ServiceHostInitializationFailed(e.ToString()); 39 | throw; 40 | } 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/Iot.DeviceEmulator/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | using System.Reflection; 7 | using System.Runtime.InteropServices; 8 | 9 | // General Information about an assembly is controlled through the following 10 | // set of attributes. Change these attribute values to modify the information 11 | // associated with an assembly. 12 | 13 | [assembly: AssemblyTitle("Iot.DeviceEmulator")] 14 | [assembly: AssemblyDescription("")] 15 | [assembly: AssemblyConfiguration("")] 16 | [assembly: AssemblyCompany("")] 17 | [assembly: AssemblyProduct("Iot.DeviceEmulator")] 18 | [assembly: AssemblyCopyright("Copyright © 2016")] 19 | [assembly: AssemblyTrademark("")] 20 | [assembly: AssemblyCulture("")] 21 | 22 | // Setting ComVisible to false makes the types in this assembly not visible 23 | // to COM components. If you need to access a type in this assembly from 24 | // COM, set the ComVisible attribute to true on that type. 25 | 26 | [assembly: ComVisible(false)] 27 | 28 | // The following GUID is for the ID of the typelib if this project is exposed to COM 29 | 30 | [assembly: Guid("5ca93865-4b0a-4dbc-9378-bdad1c396886")] 31 | 32 | // Version information for an assembly consists of the following four values: 33 | // 34 | // Major Version 35 | // Minor Version 36 | // Build Number 37 | // Revision 38 | // 39 | // You can specify all the values or you can default the Build and Revision Numbers 40 | // by using the '*' as shown below: 41 | // [assembly: AssemblyVersion("1.0.*")] 42 | 43 | [assembly: AssemblyVersion("1.0.0.0")] 44 | [assembly: AssemblyFileVersion("1.0.0.0")] -------------------------------------------------------------------------------- /src/Iot.Ingestion.RouterService/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | using System.Reflection; 7 | using System.Runtime.InteropServices; 8 | 9 | // General Information about an assembly is controlled through the following 10 | // set of attributes. Change these attribute values to modify the information 11 | // associated with an assembly. 12 | 13 | [assembly: AssemblyTitle("Iot.Ingestion.RouterService")] 14 | [assembly: AssemblyDescription("")] 15 | [assembly: AssemblyConfiguration("")] 16 | [assembly: AssemblyCompany("")] 17 | [assembly: AssemblyProduct("Iot.Ingestion.RouterService")] 18 | [assembly: AssemblyCopyright("Copyright © 2016")] 19 | [assembly: AssemblyTrademark("")] 20 | [assembly: AssemblyCulture("")] 21 | 22 | // Setting ComVisible to false makes the types in this assembly not visible 23 | // to COM components. If you need to access a type in this assembly from 24 | // COM, set the ComVisible attribute to true on that type. 25 | 26 | [assembly: ComVisible(false)] 27 | 28 | // The following GUID is for the ID of the typelib if this project is exposed to COM 29 | 30 | [assembly: Guid("09284c49-3741-4b96-8f24-95b5b99f4bf1")] 31 | 32 | // Version information for an assembly consists of the following four values: 33 | // 34 | // Major Version 35 | // Minor Version 36 | // Build Number 37 | // Revision 38 | // 39 | // You can specify all the values or you can default the Build and Revision Numbers 40 | // by using the '*' as shown below: 41 | // [assembly: AssemblyVersion("1.0.*")] 42 | 43 | [assembly: AssemblyVersion("1.0.0.0")] 44 | [assembly: AssemblyFileVersion("1.0.0.0")] -------------------------------------------------------------------------------- /src/Iot.Tenant.DataService/Startup.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Tenant.DataService 7 | { 8 | using Microsoft.AspNetCore.Builder; 9 | using Microsoft.AspNetCore.Hosting; 10 | using Microsoft.Extensions.Configuration; 11 | using Microsoft.Extensions.DependencyInjection; 12 | using Microsoft.Extensions.Logging; 13 | 14 | public class Startup 15 | { 16 | public Startup(IHostingEnvironment env) 17 | { 18 | IConfigurationBuilder builder = new ConfigurationBuilder() 19 | .SetBasePath(env.ContentRootPath) 20 | .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) 21 | .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) 22 | .AddEnvironmentVariables(); 23 | this.Configuration = builder.Build(); 24 | } 25 | 26 | public IConfigurationRoot Configuration { get; } 27 | 28 | // This method gets called by the runtime. Use this method to add services to the container. 29 | public void ConfigureServices(IServiceCollection services) 30 | { 31 | // Add framework services. 32 | services.AddMvc(); 33 | } 34 | 35 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 36 | public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 37 | { 38 | loggerFactory.AddConsole(this.Configuration.GetSection("Logging")); 39 | loggerFactory.AddDebug(); 40 | 41 | app.UseMvc(); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/Iot.Ingestion.RouterService/PackageRoot/ServiceManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Iot.Ingestion.RouterService.exe 18 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 31 | 32 | 33 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/Iot.Tenant.DataService/Iot.Tenant.DataService.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net452 5 | x64 6 | Iot.Tenant.DataService 7 | Exe 8 | True 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/Iot.Mocks/MockAsyncEnumerable.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Mocks 7 | { 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | using Microsoft.ServiceFabric.Data; 11 | using Collections = System.Collections.Generic; 12 | 13 | /// 14 | /// Simple wrapper for a synchronous IEnumerable of T. 15 | /// 16 | /// 17 | internal class MockAsyncEnumerable : IAsyncEnumerable 18 | { 19 | private Collections.IEnumerable enumerable; 20 | 21 | public MockAsyncEnumerable(Collections.IEnumerable enumerable) 22 | { 23 | this.enumerable = enumerable; 24 | } 25 | 26 | public IAsyncEnumerator GetAsyncEnumerator() 27 | { 28 | return new MockAsyncEnumerator(this.enumerable.GetEnumerator()); 29 | } 30 | } 31 | 32 | /// 33 | /// Simply wrapper for a synchronous IEnumerator of T. 34 | /// 35 | /// 36 | internal class MockAsyncEnumerator : IAsyncEnumerator 37 | { 38 | private readonly Collections.IEnumerator enumerator; 39 | 40 | public MockAsyncEnumerator(Collections.IEnumerator enumerator) 41 | { 42 | this.enumerator = enumerator; 43 | } 44 | 45 | public T Current 46 | { 47 | get { return this.enumerator.Current; } 48 | } 49 | 50 | public void Dispose() 51 | { 52 | this.enumerator.Dispose(); 53 | } 54 | 55 | public Task MoveNextAsync(CancellationToken cancellationToken) 56 | { 57 | return Task.FromResult(this.enumerator.MoveNext()); 58 | } 59 | 60 | public void Reset() 61 | { 62 | this.enumerator.Reset(); 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /src/Iot.Ingestion.Application/Iot.Ingestion.Application.sfproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | fdbd3f26-52e6-4088-b9f9-940e5fc76249 6 | 1.5 7 | 1.5 8 | 9 | 10 | 11 | Debug 12 | x64 13 | 14 | 15 | Release 16 | x64 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Service Fabric Tools\Microsoft.VisualStudio.Azure.Fabric.ApplicationProject.targets 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/Iot.Common/ServiceUriBuilder.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Common 7 | { 8 | using System; 9 | using System.Fabric; 10 | 11 | public class ServiceUriBuilder 12 | { 13 | public ServiceUriBuilder(string serviceInstance) 14 | { 15 | this.ServiceName = serviceInstance; 16 | } 17 | 18 | public ServiceUriBuilder(string applicationInstance, string serviceName) 19 | { 20 | this.ApplicationInstance = !applicationInstance.StartsWith("fabric:/") 21 | ? "fabric:/" + applicationInstance 22 | : applicationInstance; 23 | 24 | this.ServiceName = serviceName; 25 | } 26 | 27 | /// 28 | /// The name of the application instance that contains he service. 29 | /// 30 | public string ApplicationInstance { get; set; } 31 | 32 | /// 33 | /// The name of the service instance. 34 | /// 35 | public string ServiceName { get; set; } 36 | 37 | public Uri Build() 38 | { 39 | string applicationInstance = this.ApplicationInstance; 40 | 41 | if (String.IsNullOrEmpty(applicationInstance)) 42 | { 43 | try 44 | { 45 | // the ApplicationName property here automatically prepends "fabric:/" for us 46 | applicationInstance = FabricRuntime.GetActivationContext().ApplicationName; 47 | } 48 | catch (InvalidOperationException) 49 | { 50 | // FabricRuntime is not available. 51 | // This indicates that this is being called from somewhere outside the Service Fabric cluster. 52 | applicationInstance = "test"; 53 | } 54 | } 55 | 56 | return new Uri(applicationInstance.TrimEnd('/') + "/" + this.ServiceName); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/Iot.Tenant.WebService.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net452 5 | x64 6 | Iot.Tenant.WebService 7 | Exe 8 | True 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/Iot.Tenant.Application/Iot.Tenant.Application.sfproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 291371be-4218-4eec-996a-cd5b783b6cd0 6 | 1.5 7 | 1.5 8 | 9 | 10 | 11 | Debug 12 | x64 13 | 14 | 15 | Release 16 | x64 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Service Fabric Tools\Microsoft.VisualStudio.Azure.Fabric.ApplicationProject.targets 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/Iot.Admin.WebService.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net452 5 | x64 6 | Iot.Admin.WebService 7 | Exe 8 | True 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/Iot.Admin.Application/Iot.Admin.Application.sfproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 79a0b13a-6859-48c0-9517-269d788bc046 6 | 1.5 7 | 1.5 8 | 9 | 10 | 11 | Debug 12 | x64 13 | 14 | 15 | Release 16 | x64 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Service Fabric Tools\Microsoft.VisualStudio.Azure.Fabric.ApplicationProject.targets 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/Startup.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Tenant.WebService 7 | { 8 | using Microsoft.AspNetCore.Builder; 9 | using Microsoft.AspNetCore.Hosting; 10 | using Microsoft.Extensions.Configuration; 11 | using Microsoft.Extensions.DependencyInjection; 12 | using Microsoft.Extensions.Logging; 13 | 14 | public class Startup 15 | { 16 | public Startup(IHostingEnvironment env) 17 | { 18 | IConfigurationBuilder builder = new ConfigurationBuilder() 19 | .SetBasePath(env.ContentRootPath) 20 | .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) 21 | .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) 22 | .AddEnvironmentVariables(); 23 | this.Configuration = builder.Build(); 24 | } 25 | 26 | public IConfigurationRoot Configuration { get; } 27 | 28 | // This method gets called by the runtime. Use this method to add services to the container. 29 | public void ConfigureServices(IServiceCollection services) 30 | { 31 | // Add framework services. 32 | services.AddMvc(); 33 | } 34 | 35 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 36 | public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 37 | { 38 | loggerFactory.AddConsole(this.Configuration.GetSection("Logging")); 39 | loggerFactory.AddDebug(); 40 | 41 | if (env.IsDevelopment()) 42 | { 43 | app.UseDeveloperExceptionPage(); 44 | app.UseBrowserLink(); 45 | } 46 | else 47 | { 48 | app.UseExceptionHandler("/Home/Error"); 49 | } 50 | 51 | app.UseStaticFiles(); 52 | 53 | app.UseMvc( 54 | routes => 55 | { 56 | routes.MapRoute( 57 | name: "default", 58 | template: "{controller=Home}/{action=Index}/{id?}"); 59 | }); 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | html, body, div, span, applet, object, iframe, 2 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 3 | a, abbr, acronym, address, big, cite, code, 4 | del, dfn, em, img, ins, kbd, q, s, samp, 5 | small, strike, strong, sub, sup, tt, var, 6 | b, u, i, center, 7 | dl, dt, dd, ol, ul, li, 8 | fieldset, form, label, legend, 9 | table, caption, tbody, tfoot, thead, tr, th, td, 10 | article, aside, canvas, details, embed, 11 | figure, figcaption, footer, header, hgroup, 12 | menu, nav, output, ruby, section, summary, 13 | time, mark, audio, video { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; } 14 | 15 | /* HTML5 display-role reset for older browsers */ 16 | article, aside, details, figcaption, figure, 17 | footer, header, hgroup, menu, nav, section { display: block; } 18 | 19 | body { line-height: 1; font: 0.8em/1.2 Segoe UI,Arial,sans-serif; background: #333333; color: #AAAAAA; } 20 | header { height:50px; background:#111111; font-size:20px; font-weight:lighter} 21 | header h1 {display:inline-block; margin:12px; font-size: 20px; font-weight:lighter; color: #00ABEC} 22 | footer { clear: both; } 23 | 24 | /* forms */ 25 | fieldset { border: 1px solid #555555; margin: 10px 0; padding: 10px; } 26 | input[type=text] { display: inline-block; padding: 5px; background: #333333; color: #DDDDDD; border: 1px solid #555555; } 27 | button { display: block; width: 100px; padding: 3px; } 28 | 29 | a, a:visited, a:hover, a:active { color: #00ABEC; } 30 | h3 { font-size: 1.5em; font-weight: lighter; color:#FFFFFF; } 31 | h4 { font-size: 1.3em; font-weight: lighter; color:#FFFFFF; } 32 | h5 { font-size: 1.2em; font-weight: lighter; color:#DDDDDD; } 33 | ul li { list-style: none; margin: 3px 0; padding: 0; } 34 | 35 | #main { clear: both; } 36 | 37 | #result { width: 100%; padding: 10px; height:15px; margin: 1px 0; } 38 | .errorResult { border: 1px solid #DD0000; color: #DD0000; } 39 | .successResult { border: 1px solid #00DD00; color: #00DD00; } 40 | .tile { background:#444444; margin:1px 20px; padding:10px; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19) } 41 | .header { margin: 0 0 15px 0; padding: 5px; width: 340px;} 42 | #queueLength { font-size:64px; font-weight:lighter; color:#00ABEC} 43 | 44 | .deviceInfo { margin:5px 0; padding:5px; background:#222222; text-wrap: normal; word-wrap: break-word; } 45 | .deviceInfo label { display: inline-block; min-width: 75px; font-weight: bold; color:#DDDDDD; } 46 | .deviceInfo .deviceData { margin: 5px 0 } 47 | .deviceInfo a {float: right; margin-right:10px;} -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/WebService.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Admin.WebService 7 | { 8 | using System.Collections.Generic; 9 | using System.Fabric; 10 | using System.IO; 11 | using System.Threading; 12 | using System.Threading.Tasks; 13 | using Common; 14 | using Microsoft.AspNetCore.Hosting; 15 | using Microsoft.Extensions.DependencyInjection; 16 | using Microsoft.ServiceFabric.Services.Communication.Runtime; 17 | using Microsoft.ServiceFabric.Services.Runtime; 18 | using Microsoft.ServiceFabric.Services.Communication.AspNetCore; 19 | 20 | internal sealed class WebService : StatelessService 21 | { 22 | private readonly FabricClient fabricClient; 23 | 24 | public WebService(StatelessServiceContext context) 25 | : base(context) 26 | { 27 | this.fabricClient = new FabricClient(); 28 | } 29 | 30 | protected override IEnumerable CreateServiceInstanceListeners() 31 | { 32 | return new ServiceInstanceListener[1] 33 | { 34 | new ServiceInstanceListener( 35 | context => 36 | { 37 | return new WebListenerCommunicationListener( 38 | context, 39 | "ServiceEndpoint", 40 | (url, listener) => 41 | { 42 | url += "/iot"; 43 | 44 | ServiceEventSource.Current.Message($"Admin WebService starting on {url}"); 45 | 46 | return new WebHostBuilder().UseWebListener() 47 | .ConfigureServices( 48 | services => services 49 | .AddSingleton(this.fabricClient)) 50 | .UseContentRoot(Directory.GetCurrentDirectory()) 51 | .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None) 52 | .UseStartup() 53 | .UseUrls(url) 54 | .Build(); 55 | }); 56 | }) 57 | }; 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | html, body, div, span, applet, object, iframe, 2 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 3 | a, abbr, acronym, address, big, cite, code, 4 | del, dfn, em, img, ins, kbd, q, s, samp, 5 | small, strike, strong, sub, sup, tt, var, 6 | b, u, i, center, 7 | dl, dt, dd, ol, ul, li, 8 | fieldset, form, label, legend, 9 | table, caption, tbody, tfoot, thead, tr, th, td, 10 | article, aside, canvas, details, embed, 11 | figure, figcaption, footer, header, hgroup, 12 | menu, nav, output, ruby, section, summary, 13 | time, mark, audio, video { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; } 14 | 15 | /* HTML5 display-role reset for older browsers */ 16 | article, aside, details, figcaption, figure, 17 | footer, header, hgroup, menu, nav, section { display: block; } 18 | 19 | body { line-height: 1; font: 0.8em/1.2 Segoe UI,Arial,sans-serif; background: #333333; color: #AAAAAA; } 20 | header { height:50px; background:#111111;} 21 | footer { clear: both; } 22 | 23 | /* forms */ 24 | fieldset { border: 1px solid #555555; margin: 10px 0; padding: 10px; } 25 | input[type=text] { display: inline-block; padding: 5px; background: #333333; color: #DDDDDD; border: 1px solid #555555; } 26 | button { display: block; width: 100px; padding: 3px; } 27 | 28 | a, a:visited, a:hover, a:active { color: #00ABEC; } 29 | h3 { font-size: 1.5em; font-weight: lighter; color:#FFFFFF; } 30 | h4 { font-size: 1.3em; font-weight: lighter; color:#FFFFFF; } 31 | h5 { font-size: 1.2em; font-weight: lighter; color:#DDDDDD; } 32 | ul li { list-style: none; margin: 3px 0; padding: 0; } 33 | 34 | #main { clear: both; } 35 | 36 | #result { width: 100%; padding: 10px; height:15px; margin: 1px 0; } 37 | .errorResult { border: 1px solid #DD0000; color: #DD0000; } 38 | .successResult { border: 1px solid #00DD00; color: #00DD00; } 39 | 40 | .column { float:left; margin:0 10px; } 41 | .columnHeader { margin: 10px 0 } 42 | .tile { background:#444444; margin:1px 0; padding:10px; width:350px; min-height:300px; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19) } 43 | .header { margin: 0 0 15px 0; padding: 5px; width: 340px;} 44 | 45 | .addApplication { margin: 20px 0 } 46 | .addApplication label { font-size: 12px; } 47 | .addApplication input[type=text] { width: 340px; margin: 2px 0 8px 0; } 48 | 49 | .applicationInfo { width:330px; margin:5px 0; padding:10px; background:#222222; border: 1px solid; text-wrap: normal; word-wrap: break-word; } 50 | .applicationInfo label { display: inline-block; width: 100px; font-weight: bold; color:#DDDDDD; } 51 | .applicationInfo .applicationDetails { margin: 20px 0 } 52 | 53 | /* application and service statuses */ 54 | .ready { border-color: #00ABEC; } 55 | .creating { border-color: #D17D00; } 56 | .active { border-color: #00ABEC; } 57 | .upgrading { border-color: #00C69F; } 58 | .deleting { border-color: #AAAAAA; } 59 | -------------------------------------------------------------------------------- /src/Iot.Tenant.DataService/Controllers/DevicesController.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Tenant.DataService.Controllers 7 | { 8 | using System.Collections.Generic; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | using Iot.Tenant.DataService.Models; 12 | using Microsoft.AspNetCore.Mvc; 13 | using Microsoft.ServiceFabric.Data; 14 | using Microsoft.ServiceFabric.Data.Collections; 15 | using Common; 16 | using Microsoft.AspNetCore.Hosting; 17 | 18 | [Route("api/[controller]")] 19 | public class DevicesController : Controller 20 | { 21 | private readonly IApplicationLifetime appLifetime; 22 | 23 | private readonly IReliableStateManager stateManager; 24 | 25 | public DevicesController(IReliableStateManager stateManager, IApplicationLifetime appLifetime) 26 | { 27 | this.stateManager = stateManager; 28 | this.appLifetime = appLifetime; 29 | } 30 | 31 | 32 | [HttpGet] 33 | [Route("")] 34 | public async Task GetAsync() 35 | { 36 | IReliableDictionary store = 37 | await this.stateManager.GetOrAddAsync>(DataService.EventDictionaryName); 38 | 39 | List devices = new List(); 40 | using (ITransaction tx = this.stateManager.CreateTransaction()) 41 | { 42 | IAsyncEnumerable> enumerable = await store.CreateEnumerableAsync(tx); 43 | IAsyncEnumerator> enumerator = enumerable.GetAsyncEnumerator(); 44 | 45 | while (await enumerator.MoveNextAsync(appLifetime.ApplicationStopping)) 46 | { 47 | devices.Add( 48 | new 49 | { 50 | Id = enumerator.Current.Key, 51 | Timestamp = enumerator.Current.Value.Timestamp 52 | }); 53 | } 54 | } 55 | 56 | return this.Ok(devices); 57 | } 58 | 59 | [HttpGet] 60 | [Route("queue/length")] 61 | public async Task GetQueueLengthAsync() 62 | { 63 | IReliableQueue queue = 64 | await this.stateManager.GetOrAddAsync>(DataService.EventQueueName); 65 | 66 | using (ITransaction tx = this.stateManager.CreateTransaction()) 67 | { 68 | long count = await queue.GetCountAsync(tx); 69 | 70 | return this.Ok(count); 71 | } 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/WebService.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Tenant.WebService 7 | { 8 | using Common; 9 | using Microsoft.AspNetCore.Hosting; 10 | using Microsoft.Extensions.DependencyInjection; 11 | using Microsoft.ServiceFabric.Services.Communication.AspNetCore; 12 | using Microsoft.ServiceFabric.Services.Communication.Runtime; 13 | using Microsoft.ServiceFabric.Services.Runtime; 14 | using System; 15 | using System.Collections.Generic; 16 | using System.Fabric; 17 | using System.IO; 18 | using System.Linq; 19 | using System.Net.Http; 20 | 21 | internal sealed class WebService : StatelessService 22 | { 23 | public WebService(StatelessServiceContext context) 24 | : base(context) 25 | { 26 | } 27 | 28 | protected override IEnumerable CreateServiceInstanceListeners() 29 | { 30 | return new ServiceInstanceListener[1] 31 | { 32 | new ServiceInstanceListener( 33 | context => 34 | new WebListenerCommunicationListener( 35 | context, 36 | "ServiceEndpoint", 37 | (url, listener) => 38 | { 39 | // in this sample, tenant application names always have the form "fabric:/Iot.Tenant/ 40 | // This extracts the tenant name from the application name and uses it as the web application path. 41 | string tenantName = new Uri(context.CodePackageActivationContext.ApplicationName).Segments.Last(); 42 | url += $"/{tenantName}"; 43 | 44 | ServiceEventSource.Current.Message($"Listening on {url}"); 45 | 46 | return new WebHostBuilder() 47 | .UseWebListener() 48 | .ConfigureServices( 49 | services => services 50 | .AddSingleton(context) 51 | .AddSingleton(new FabricClient()) 52 | .AddSingleton(new HttpClient(new HttpServiceClientHandler()))) 53 | .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None) 54 | .UseContentRoot(Directory.GetCurrentDirectory()) 55 | .UseStartup() 56 | .UseUrls(url) 57 | .Build(); 58 | }) 59 | ) 60 | }; 61 | } 62 | 63 | } 64 | } -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/Startup.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Admin.WebService 7 | { 8 | using System; 9 | using System.Threading.Tasks; 10 | using Microsoft.AspNetCore.Builder; 11 | using Microsoft.AspNetCore.Diagnostics; 12 | using Microsoft.AspNetCore.Hosting; 13 | using Microsoft.AspNetCore.Http; 14 | using Microsoft.Extensions.Configuration; 15 | using Microsoft.Extensions.DependencyInjection; 16 | using Microsoft.Extensions.Logging; 17 | 18 | public class Startup 19 | { 20 | public Startup(IHostingEnvironment env) 21 | { 22 | IConfigurationBuilder builder = new ConfigurationBuilder() 23 | .SetBasePath(env.ContentRootPath) 24 | .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) 25 | .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) 26 | .AddEnvironmentVariables(); 27 | this.Configuration = builder.Build(); 28 | } 29 | 30 | public IConfigurationRoot Configuration { get; } 31 | 32 | // This method gets called by the runtime. Use this method to add services to the container. 33 | public void ConfigureServices(IServiceCollection services) 34 | { 35 | // Add framework services. 36 | services.AddMvc(); 37 | } 38 | 39 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 40 | public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 41 | { 42 | loggerFactory.AddConsole(this.Configuration.GetSection("Logging")); 43 | loggerFactory.AddDebug(); 44 | 45 | if (env.IsDevelopment()) 46 | { 47 | app.UseDeveloperExceptionPage(); 48 | app.UseBrowserLink(); 49 | } 50 | 51 | app.UseExceptionHandler( 52 | errorApp => 53 | errorApp.Run( 54 | context => 55 | { 56 | context.Response.StatusCode = 500; 57 | context.Response.ContentType = "text/plain"; 58 | 59 | IExceptionHandlerFeature feature = context.Features.Get(); 60 | if (feature != null) 61 | { 62 | Exception ex = feature.Error; 63 | 64 | return context.Response.WriteAsync(ex.Message); 65 | } 66 | 67 | return Task.FromResult(true); 68 | })); 69 | 70 | app.UseStaticFiles(); 71 | 72 | app.UseMvc( 73 | routes => 74 | { 75 | routes.MapRoute( 76 | name: "default", 77 | template: "{controller=Home}/{action=Index}/{id?}"); 78 | }); 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Home Page"; 3 | } 4 | 5 |
6 |
7 |
8 |

Device event streams queued for processing:

9 |
Loading..
10 |
11 |
12 |

Devices

13 |
    14 |
    15 |
    16 | 17 | @section scripts 18 | { 19 | 96 | } -------------------------------------------------------------------------------- /src/Iot.DeviceEmulator/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | pkg/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | 24 | # Visual Studio 2015 cache/options directory 25 | .vs/ 26 | 27 | # MSTest test Results 28 | [Tt]est[Rr]esult*/ 29 | [Bb]uild[Ll]og.* 30 | 31 | # NUNIT 32 | *.VisualState.xml 33 | TestResult.xml 34 | 35 | # Build Results of an ATL Project 36 | [Dd]ebugPS/ 37 | [Rr]eleasePS/ 38 | dlldata.c 39 | 40 | # DNX 41 | project.lock.json 42 | artifacts/ 43 | 44 | *_i.c 45 | *_p.c 46 | *_i.h 47 | *.ilk 48 | *.meta 49 | *.obj 50 | *.pch 51 | *.pdb 52 | *.pgc 53 | *.pgd 54 | *.rsp 55 | *.sbr 56 | *.tlb 57 | *.tli 58 | *.tlh 59 | *.tmp 60 | *.tmp_proj 61 | *.log 62 | *.vspscc 63 | *.vssscc 64 | .builds 65 | *.pidb 66 | *.svclog 67 | *.scc 68 | 69 | # Chutzpah Test files 70 | _Chutzpah* 71 | 72 | # Visual C++ cache files 73 | ipch/ 74 | *.aps 75 | *.ncb 76 | *.opensdf 77 | *.sdf 78 | *.cachefile 79 | 80 | # Visual Studio profiler 81 | *.psess 82 | *.vsp 83 | *.vspx 84 | 85 | # TFS 2012 Local Workspace 86 | $tf/ 87 | 88 | # Guidance Automation Toolkit 89 | *.gpState 90 | 91 | # ReSharper is a .NET coding add-in 92 | _ReSharper*/ 93 | *.[Rr]e[Ss]harper 94 | *.DotSettings.user 95 | 96 | # JustCode is a .NET coding add-in 97 | .JustCode 98 | 99 | # TeamCity is a build add-in 100 | _TeamCity* 101 | 102 | # DotCover is a Code Coverage Tool 103 | *.dotCover 104 | 105 | # NCrunch 106 | _NCrunch_* 107 | .*crunch*.local.xml 108 | 109 | # MightyMoose 110 | *.mm.* 111 | AutoTest.Net/ 112 | 113 | # Web workbench (sass) 114 | .sass-cache/ 115 | 116 | # Installshield output folder 117 | [Ee]xpress/ 118 | 119 | # DocProject is a documentation generator add-in 120 | DocProject/buildhelp/ 121 | DocProject/Help/*.HxT 122 | DocProject/Help/*.HxC 123 | DocProject/Help/*.hhc 124 | DocProject/Help/*.hhk 125 | DocProject/Help/*.hhp 126 | DocProject/Help/Html2 127 | DocProject/Help/html 128 | 129 | # Click-Once directory 130 | publish/ 131 | 132 | # Publish Web Output 133 | *.[Pp]ublish.xml 134 | *.azurePubxml 135 | ## TODO: Comment the next line if you want to checkin your 136 | ## web deploy settings but do note that will include unencrypted 137 | ## passwords 138 | #*.pubxml 139 | 140 | *.publishproj 141 | 142 | # NuGet Packages 143 | *.nupkg 144 | # The packages folder can be ignored because of Package Restore 145 | **/packages/* 146 | # except build/, which is used as an MSBuild target. 147 | !**/packages/build/ 148 | # Uncomment if necessary however generally it will be regenerated when needed 149 | #!**/packages/repositories.config 150 | 151 | # Windows Azure Build Output 152 | csx/ 153 | *.build.csdef 154 | 155 | # Windows Store app package directory 156 | AppPackages/ 157 | 158 | # Visual Studio cache files 159 | # files ending in .cache can be ignored 160 | *.[Cc]ache 161 | # but keep track of directories ending in .cache 162 | !*.[Cc]ache/ 163 | 164 | # Others 165 | ClientBin/ 166 | [Ss]tyle[Cc]op.* 167 | ~$* 168 | *~ 169 | *.dbmdl 170 | *.dbproj.schemaview 171 | *.pfx 172 | *.publishsettings 173 | node_modules/ 174 | orleans.codegen.cs 175 | 176 | # RIA/Silverlight projects 177 | Generated_Code/ 178 | 179 | # Backup & report files from converting an old project file 180 | # to a newer Visual Studio version. Backup files are not needed, 181 | # because we have git ;-) 182 | _UpgradeReport_Files/ 183 | Backup*/ 184 | UpgradeLog*.XML 185 | UpgradeLog*.htm 186 | 187 | # SQL Server files 188 | *.mdf 189 | *.ldf 190 | 191 | # Business Intelligence projects 192 | *.rdl.data 193 | *.bim.layout 194 | *.bim_*.settings 195 | 196 | # Microsoft Fakes 197 | FakesAssemblies/ 198 | 199 | # Node.js Tools for Visual Studio 200 | .ntvs_analysis.dat 201 | 202 | # Visual Studio 6 build log 203 | *.plg 204 | 205 | # Visual Studio 6 workspace options file 206 | *.opt 207 | 208 | # LightSwitch generated files 209 | GeneratedArtifacts/ 210 | _Pvt_Extensions/ 211 | ModelManifest.xml 212 | -------------------------------------------------------------------------------- /src/Iot.Tenant.DataService/Controllers/EventsController.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Tenant.DataService.Controllers 7 | { 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using System.Threading; 12 | using System.Threading.Tasks; 13 | using Iot.Tenant.DataService.Models; 14 | using Microsoft.AspNetCore.Mvc; 15 | using Microsoft.ServiceFabric.Data; 16 | using Microsoft.ServiceFabric.Data.Collections; 17 | using System.Fabric; 18 | using Common; 19 | using Microsoft.AspNetCore.Hosting; 20 | 21 | [Route("api/[controller]")] 22 | public class EventsController : Controller 23 | { 24 | private readonly IApplicationLifetime appLifetime; 25 | 26 | private readonly IReliableStateManager stateManager; 27 | 28 | private readonly StatefulServiceContext context; 29 | 30 | public EventsController(IReliableStateManager stateManager, StatefulServiceContext context, IApplicationLifetime appLifetime) 31 | { 32 | this.stateManager = stateManager; 33 | this.context = context; 34 | this.appLifetime = appLifetime; 35 | } 36 | 37 | 38 | [HttpPost] 39 | [Route("{deviceId}")] 40 | public async Task Post(string deviceId, [FromBody] IEnumerable events) 41 | { 42 | if (String.IsNullOrEmpty(deviceId)) 43 | { 44 | return this.BadRequest(); 45 | } 46 | 47 | if (events == null) 48 | { 49 | return this.BadRequest(); 50 | } 51 | 52 | ServiceEventSource.Current.ServiceMessage( 53 | this.context, 54 | "Received {0} events from device {1}", 55 | events.Count(), 56 | deviceId); 57 | 58 | DeviceEvent max = events.FirstOrDefault(); 59 | 60 | if (max == null) 61 | { 62 | return this.Ok(); 63 | } 64 | 65 | DeviceEventSeries eventList = new DeviceEventSeries(deviceId, events); 66 | 67 | IReliableDictionary store = 68 | await this.stateManager.GetOrAddAsync>(DataService.EventDictionaryName); 69 | 70 | IReliableQueue queue = 71 | await this.stateManager.GetOrAddAsync>(DataService.EventQueueName); 72 | 73 | // determine the most recent event in the time series 74 | foreach (DeviceEvent item in events) 75 | { 76 | this.appLifetime.ApplicationStopping.ThrowIfCancellationRequested(); 77 | 78 | if (item.Timestamp > max.Timestamp) 79 | { 80 | max = item; 81 | } 82 | } 83 | 84 | using (ITransaction tx = this.stateManager.CreateTransaction()) 85 | { 86 | // Update the current value if the max in the new set is more recent 87 | // Or add the max in the current set if a value for this device doesn't exist. 88 | await store.AddOrUpdateAsync( 89 | tx, 90 | deviceId, 91 | max, 92 | (key, currentValue) => 93 | { 94 | return max.Timestamp > currentValue.Timestamp 95 | ? max 96 | : currentValue; 97 | }); 98 | 99 | // Queue the time series for offload 100 | await queue.EnqueueAsync(tx, eventList); 101 | 102 | // Commit 103 | await tx.CommitAsync(); 104 | } 105 | 106 | return this.Ok(); 107 | } 108 | } 109 | } -------------------------------------------------------------------------------- /src/Iot.Mocks/MockReliableQueue.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Mocks 7 | { 8 | using System; 9 | using System.Collections.Concurrent; 10 | using System.Threading; 11 | using System.Threading.Tasks; 12 | using Microsoft.ServiceFabric.Data; 13 | using Microsoft.ServiceFabric.Data.Collections; 14 | 15 | public class MockReliableQueue : IReliableQueue 16 | { 17 | private ConcurrentQueue queue = new ConcurrentQueue(); 18 | 19 | public Task EnqueueAsync(ITransaction tx, T item, TimeSpan timeout, CancellationToken cancellationToken) 20 | { 21 | this.queue.Enqueue(item); 22 | 23 | return Task.FromResult(true); 24 | } 25 | 26 | public Task EnqueueAsync(ITransaction tx, T item) 27 | { 28 | this.queue.Enqueue(item); 29 | 30 | return Task.FromResult(true); 31 | } 32 | 33 | public Task> TryDequeueAsync(ITransaction tx, TimeSpan timeout, CancellationToken cancellationToken) 34 | { 35 | T item; 36 | bool result = this.queue.TryDequeue(out item); 37 | 38 | return Task.FromResult((ConditionalValue) Activator.CreateInstance(typeof(ConditionalValue), result, item)); 39 | } 40 | 41 | public Task> TryDequeueAsync(ITransaction tx) 42 | { 43 | T item; 44 | bool result = this.queue.TryDequeue(out item); 45 | 46 | return Task.FromResult((ConditionalValue) Activator.CreateInstance(typeof(ConditionalValue), result, item)); 47 | } 48 | 49 | public Task> TryPeekAsync(ITransaction tx, LockMode lockMode, TimeSpan timeout, CancellationToken cancellationToken) 50 | { 51 | T item; 52 | bool result = this.queue.TryPeek(out item); 53 | 54 | return Task.FromResult((ConditionalValue) Activator.CreateInstance(typeof(ConditionalValue), result, item)); 55 | } 56 | 57 | public Task> TryPeekAsync(ITransaction tx, LockMode lockMode) 58 | { 59 | T item; 60 | bool result = this.queue.TryPeek(out item); 61 | 62 | return Task.FromResult((ConditionalValue) Activator.CreateInstance(typeof(ConditionalValue), result, item)); 63 | } 64 | 65 | public Task> TryPeekAsync(ITransaction tx, TimeSpan timeout, CancellationToken cancellationToken) 66 | { 67 | T item; 68 | bool result = this.queue.TryPeek(out item); 69 | 70 | return Task.FromResult((ConditionalValue) Activator.CreateInstance(typeof(ConditionalValue), result, item)); 71 | } 72 | 73 | public Task> TryPeekAsync(ITransaction tx) 74 | { 75 | T item; 76 | bool result = this.queue.TryPeek(out item); 77 | 78 | return Task.FromResult((ConditionalValue) Activator.CreateInstance(typeof(ConditionalValue), result, item)); 79 | } 80 | 81 | public Task ClearAsync() 82 | { 83 | while (!this.queue.IsEmpty) 84 | { 85 | T result; 86 | this.queue.TryDequeue(out result); 87 | } 88 | 89 | return Task.FromResult(true); 90 | } 91 | 92 | public Task> CreateEnumerableAsync(ITransaction tx) 93 | { 94 | return Task.FromResult>(new MockAsyncEnumerable(this.queue)); 95 | } 96 | 97 | public Task GetCountAsync(ITransaction tx) 98 | { 99 | return Task.FromResult(this.queue.Count); 100 | } 101 | 102 | public Uri Name { get; set; } 103 | 104 | public Task GetCountAsync() 105 | { 106 | return Task.FromResult((long) this.queue.Count); 107 | } 108 | } 109 | } -------------------------------------------------------------------------------- /src/Iot.Tenant.DataService.Tests/DevicesControllerTests.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Tenant.DataService.Tests 7 | { 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using System.Threading; 12 | using System.Threading.Tasks; 13 | using Iot.Mocks; 14 | using Iot.Tenant.DataService.Controllers; 15 | using Iot.Tenant.DataService.Models; 16 | using Microsoft.AspNetCore.Mvc; 17 | using Microsoft.ServiceFabric.Data; 18 | using Microsoft.ServiceFabric.Data.Collections; 19 | using Xunit; 20 | using Common; 21 | 22 | public class DevicesControllerTests 23 | { 24 | 25 | [Fact] 26 | public async Task GetAll() 27 | { 28 | MockApplicationLifetime appLifetime = new MockApplicationLifetime(); 29 | MockReliableStateManager stateManager = new MockReliableStateManager(); 30 | 31 | IReliableDictionary store = 32 | await stateManager.GetOrAddAsync>(DataService.EventDictionaryName); 33 | 34 | Dictionary expected = new Dictionary(); 35 | expected.Add("device1", new DeviceEvent(DateTimeOffset.UtcNow.Subtract(TimeSpan.FromMinutes(1)))); 36 | expected.Add("device2", new DeviceEvent(DateTimeOffset.UtcNow.Subtract(TimeSpan.FromMinutes(2)))); 37 | 38 | 39 | using (ITransaction tx = stateManager.CreateTransaction()) 40 | { 41 | foreach (var item in expected) 42 | { 43 | await store.SetAsync(tx, item.Key, item.Value); 44 | } 45 | } 46 | 47 | DevicesController target = new DevicesController(stateManager, appLifetime); 48 | IActionResult result = await target.GetAsync(); 49 | 50 | Assert.True(result is OkObjectResult); 51 | 52 | IEnumerable actual = ((OkObjectResult) result).Value as IEnumerable; 53 | 54 | foreach (dynamic item in actual) 55 | { 56 | Assert.Equal< DateTimeOffset>(expected[item.Id].Timestamp, item.Timestamp); 57 | } 58 | } 59 | 60 | [Fact] 61 | public async Task GetAllEmpty() 62 | { 63 | MockApplicationLifetime appLifetime = new MockApplicationLifetime(); 64 | MockReliableStateManager stateManager = new MockReliableStateManager(); 65 | 66 | IReliableDictionary store = 67 | await stateManager.GetOrAddAsync>(DataService.EventDictionaryName); 68 | 69 | DevicesController target = new DevicesController(stateManager, appLifetime); 70 | IActionResult result = await target.GetAsync(); 71 | 72 | Assert.True(result is OkObjectResult); 73 | 74 | IEnumerable actual = ((OkObjectResult) result).Value as IEnumerable; 75 | 76 | Assert.False(actual.Any()); 77 | } 78 | 79 | [Fact] 80 | public async Task GetQueueLength() 81 | { 82 | MockApplicationLifetime appLifetime = new MockApplicationLifetime(); 83 | MockReliableStateManager stateManager = new MockReliableStateManager(); 84 | 85 | IReliableQueue queue = 86 | await stateManager.GetOrAddAsync>(DataService.EventQueueName); 87 | 88 | using (ITransaction tx = stateManager.CreateTransaction()) 89 | { 90 | await queue.EnqueueAsync(tx, new DeviceEventSeries("", new DeviceEvent[0])); 91 | } 92 | 93 | DevicesController target = new DevicesController(stateManager, appLifetime); 94 | IActionResult result = await target.GetQueueLengthAsync(); 95 | 96 | Assert.True(result is OkObjectResult); 97 | long actual = (long) ((OkObjectResult) result).Value; 98 | 99 | Assert.Equal(1, actual); 100 | } 101 | } 102 | } -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | ** Unobtrusive validation support library for jQuery and jQuery Validate 3 | ** Copyright (C) Microsoft Corporation. All rights reserved. 4 | */ 5 | !function(a){function e(a,e,n){a.rules[e]=n,a.message&&(a.messages[e]=a.message)}function n(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function t(a){return a.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function r(a){return a.substr(0,a.lastIndexOf(".")+1)}function i(a,e){return 0===a.indexOf("*.")&&(a=a.replace("*.",e)),a}function o(e,n){var r=a(this).find("[data-valmsg-for='"+t(n[0].name)+"']"),i=r.attr("data-valmsg-replace"),o=i?a.parseJSON(i)!==!1:null;r.removeClass("field-validation-valid").addClass("field-validation-error"),e.data("unobtrusiveContainer",r),o?(r.empty(),e.removeClass("input-validation-error").appendTo(r)):e.hide()}function d(e,n){var t=a(this).find("[data-valmsg-summary=true]"),r=t.find("ul");r&&r.length&&n.errorList.length&&(r.empty(),t.addClass("validation-summary-errors").removeClass("validation-summary-valid"),a.each(n.errorList,function(){a("
  • ").html(this.message).appendTo(r)}))}function s(e){var n=e.data("unobtrusiveContainer");if(n){var t=n.attr("data-valmsg-replace"),r=t?a.parseJSON(t):null;n.addClass("field-validation-valid").removeClass("field-validation-error"),e.removeData("unobtrusiveContainer"),r&&n.empty()}}function l(e){var n=a(this),t="__jquery_unobtrusive_validation_form_reset";if(!n.data(t)){n.data(t,!0);try{n.data("validator").resetForm()}finally{n.removeData(t)}n.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors"),n.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}}function m(e){var n=a(e),t=n.data(v),r=a.proxy(l,e),i=p.unobtrusive.options||{},m=function(n,t){var r=i[n];r&&a.isFunction(r)&&r.apply(e,t)};return t||(t={options:{errorClass:i.errorClass||"input-validation-error",errorElement:i.errorElement||"span",errorPlacement:function(){o.apply(e,arguments),m("errorPlacement",arguments)},invalidHandler:function(){d.apply(e,arguments),m("invalidHandler",arguments)},messages:{},rules:{},success:function(){s.apply(e,arguments),m("success",arguments)}},attachValidation:function(){n.off("reset."+v,r).on("reset."+v,r).validate(this.options)},validate:function(){return n.validate(),n.valid()}},n.data(v,t)),t}var u,p=a.validator,v="unobtrusiveValidation";p.unobtrusive={adapters:[],parseElement:function(e,n){var t,r,i,o=a(e),d=o.parents("form")[0];d&&(t=m(d),t.options.rules[e.name]=r={},t.options.messages[e.name]=i={},a.each(this.adapters,function(){var n="data-val-"+this.name,t=o.attr(n),s={};void 0!==t&&(n+="-",a.each(this.params,function(){s[this]=o.attr(n+this)}),this.adapt({element:e,form:d,message:t,params:s,rules:r,messages:i}))}),a.extend(r,{__dummy__:!0}),n||t.attachValidation())},parse:function(e){var n=a(e),t=n.parents().addBack().filter("form").add(n.find("form")).has("[data-val=true]");n.find("[data-val=true]").each(function(){p.unobtrusive.parseElement(this,!0)}),t.each(function(){var a=m(this);a&&a.attachValidation()})}},u=p.unobtrusive.adapters,u.add=function(a,e,n){return n||(n=e,e=[]),this.push({name:a,params:e,adapt:n}),this},u.addBool=function(a,n){return this.add(a,function(t){e(t,n||a,!0)})},u.addMinMax=function(a,n,t,r,i,o){return this.add(a,[i||"min",o||"max"],function(a){var i=a.params.min,o=a.params.max;i&&o?e(a,r,[i,o]):i?e(a,n,i):o&&e(a,t,o)})},u.addSingleVal=function(a,n,t){return this.add(a,[n||"val"],function(r){e(r,t||a,r.params[n])})},p.addMethod("__dummy__",function(a,e,n){return!0}),p.addMethod("regex",function(a,e,n){var t;return this.optional(e)?!0:(t=new RegExp(n).exec(a),t&&0===t.index&&t[0].length===a.length)}),p.addMethod("nonalphamin",function(a,e,n){var t;return n&&(t=a.match(/\W/g),t=t&&t.length>=n),t}),p.methods.extension?(u.addSingleVal("accept","mimtype"),u.addSingleVal("extension","extension")):u.addSingleVal("extension","extension","accept"),u.addSingleVal("regex","pattern"),u.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"),u.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range"),u.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength"),u.add("equalto",["other"],function(n){var o=r(n.element.name),d=n.params.other,s=i(d,o),l=a(n.form).find(":input").filter("[name='"+t(s)+"']")[0];e(n,"equalTo",l)}),u.add("required",function(a){("INPUT"!==a.element.tagName.toUpperCase()||"CHECKBOX"!==a.element.type.toUpperCase())&&e(a,"required",!0)}),u.add("remote",["url","type","additionalfields"],function(o){var d={url:o.params.url,type:o.params.type||"GET",data:{}},s=r(o.element.name);a.each(n(o.params.additionalfields||o.element.name),function(e,n){var r=i(n,s);d.data[r]=function(){var e=a(o.form).find(":input").filter("[name='"+t(r)+"']");return e.is(":checkbox")?e.filter(":checked").val()||e.filter(":hidden").val()||"":e.is(":radio")?e.filter(":checked").val()||"":e.val()}}),e(o,"remote",d)}),u.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&e(a,"minlength",a.params.min),a.params.nonalphamin&&e(a,"nonalphamin",a.params.nonalphamin),a.params.regex&&e(a,"regex",a.params.regex)}),a(function(){p.unobtrusive.parse(document)})}(jQuery); -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | ** Unobtrusive validation support library for jQuery and jQuery Validate 3 | ** Copyright (C) Microsoft Corporation. All rights reserved. 4 | */ 5 | !function(a){function e(a,e,n){a.rules[e]=n,a.message&&(a.messages[e]=a.message)}function n(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function t(a){return a.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function r(a){return a.substr(0,a.lastIndexOf(".")+1)}function i(a,e){return 0===a.indexOf("*.")&&(a=a.replace("*.",e)),a}function o(e,n){var r=a(this).find("[data-valmsg-for='"+t(n[0].name)+"']"),i=r.attr("data-valmsg-replace"),o=i?a.parseJSON(i)!==!1:null;r.removeClass("field-validation-valid").addClass("field-validation-error"),e.data("unobtrusiveContainer",r),o?(r.empty(),e.removeClass("input-validation-error").appendTo(r)):e.hide()}function d(e,n){var t=a(this).find("[data-valmsg-summary=true]"),r=t.find("ul");r&&r.length&&n.errorList.length&&(r.empty(),t.addClass("validation-summary-errors").removeClass("validation-summary-valid"),a.each(n.errorList,function(){a("
  • ").html(this.message).appendTo(r)}))}function s(e){var n=e.data("unobtrusiveContainer");if(n){var t=n.attr("data-valmsg-replace"),r=t?a.parseJSON(t):null;n.addClass("field-validation-valid").removeClass("field-validation-error"),e.removeData("unobtrusiveContainer"),r&&n.empty()}}function l(e){var n=a(this),t="__jquery_unobtrusive_validation_form_reset";if(!n.data(t)){n.data(t,!0);try{n.data("validator").resetForm()}finally{n.removeData(t)}n.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors"),n.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}}function m(e){var n=a(e),t=n.data(v),r=a.proxy(l,e),i=p.unobtrusive.options||{},m=function(n,t){var r=i[n];r&&a.isFunction(r)&&r.apply(e,t)};return t||(t={options:{errorClass:i.errorClass||"input-validation-error",errorElement:i.errorElement||"span",errorPlacement:function(){o.apply(e,arguments),m("errorPlacement",arguments)},invalidHandler:function(){d.apply(e,arguments),m("invalidHandler",arguments)},messages:{},rules:{},success:function(){s.apply(e,arguments),m("success",arguments)}},attachValidation:function(){n.off("reset."+v,r).on("reset."+v,r).validate(this.options)},validate:function(){return n.validate(),n.valid()}},n.data(v,t)),t}var u,p=a.validator,v="unobtrusiveValidation";p.unobtrusive={adapters:[],parseElement:function(e,n){var t,r,i,o=a(e),d=o.parents("form")[0];d&&(t=m(d),t.options.rules[e.name]=r={},t.options.messages[e.name]=i={},a.each(this.adapters,function(){var n="data-val-"+this.name,t=o.attr(n),s={};void 0!==t&&(n+="-",a.each(this.params,function(){s[this]=o.attr(n+this)}),this.adapt({element:e,form:d,message:t,params:s,rules:r,messages:i}))}),a.extend(r,{__dummy__:!0}),n||t.attachValidation())},parse:function(e){var n=a(e),t=n.parents().addBack().filter("form").add(n.find("form")).has("[data-val=true]");n.find("[data-val=true]").each(function(){p.unobtrusive.parseElement(this,!0)}),t.each(function(){var a=m(this);a&&a.attachValidation()})}},u=p.unobtrusive.adapters,u.add=function(a,e,n){return n||(n=e,e=[]),this.push({name:a,params:e,adapt:n}),this},u.addBool=function(a,n){return this.add(a,function(t){e(t,n||a,!0)})},u.addMinMax=function(a,n,t,r,i,o){return this.add(a,[i||"min",o||"max"],function(a){var i=a.params.min,o=a.params.max;i&&o?e(a,r,[i,o]):i?e(a,n,i):o&&e(a,t,o)})},u.addSingleVal=function(a,n,t){return this.add(a,[n||"val"],function(r){e(r,t||a,r.params[n])})},p.addMethod("__dummy__",function(a,e,n){return!0}),p.addMethod("regex",function(a,e,n){var t;return this.optional(e)?!0:(t=new RegExp(n).exec(a),t&&0===t.index&&t[0].length===a.length)}),p.addMethod("nonalphamin",function(a,e,n){var t;return n&&(t=a.match(/\W/g),t=t&&t.length>=n),t}),p.methods.extension?(u.addSingleVal("accept","mimtype"),u.addSingleVal("extension","extension")):u.addSingleVal("extension","extension","accept"),u.addSingleVal("regex","pattern"),u.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"),u.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range"),u.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength"),u.add("equalto",["other"],function(n){var o=r(n.element.name),d=n.params.other,s=i(d,o),l=a(n.form).find(":input").filter("[name='"+t(s)+"']")[0];e(n,"equalTo",l)}),u.add("required",function(a){("INPUT"!==a.element.tagName.toUpperCase()||"CHECKBOX"!==a.element.type.toUpperCase())&&e(a,"required",!0)}),u.add("remote",["url","type","additionalfields"],function(o){var d={url:o.params.url,type:o.params.type||"GET",data:{}},s=r(o.element.name);a.each(n(o.params.additionalfields||o.element.name),function(e,n){var r=i(n,s);d.data[r]=function(){var e=a(o.form).find(":input").filter("[name='"+t(r)+"']");return e.is(":checkbox")?e.filter(":checked").val()||e.filter(":hidden").val()||"":e.is(":radio")?e.filter(":checked").val()||"":e.val()}}),e(o,"remote",d)}),u.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&e(a,"minlength",a.params.min),a.params.nonalphamin&&e(a,"nonalphamin",a.params.nonalphamin),a.params.regex&&e(a,"regex",a.params.regex)}),a(function(){p.unobtrusive.parse(document)})}(jQuery); -------------------------------------------------------------------------------- /src/Iot.Tenant.WebService/Controllers/DevicesController.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Tenant.WebService.Controllers 7 | { 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Fabric; 11 | using System.Fabric.Query; 12 | using System.IO; 13 | using System.Net.Http; 14 | using System.Threading; 15 | using System.Threading.Tasks; 16 | using Iot.Common; 17 | using Iot.Tenant.WebService.ViewModels; 18 | using Microsoft.AspNetCore.Mvc; 19 | using Newtonsoft.Json; 20 | using Microsoft.AspNetCore.Hosting; 21 | 22 | [Route("api/[controller]")] 23 | public class DevicesController : Controller 24 | { 25 | private const string TenantDataServiceName = "DataService"; 26 | private readonly FabricClient fabricClient; 27 | private readonly IApplicationLifetime appLifetime; 28 | private readonly HttpClient httpClient; 29 | 30 | public DevicesController(FabricClient fabricClient, HttpClient httpClient, IApplicationLifetime appLifetime) 31 | { 32 | this.fabricClient = fabricClient; 33 | this.httpClient = httpClient; 34 | this.appLifetime = appLifetime; 35 | } 36 | 37 | [HttpGet] 38 | [Route("queue/length")] 39 | public async Task GetQueueLengthAsync() 40 | { 41 | ServiceUriBuilder uriBuilder = new ServiceUriBuilder(TenantDataServiceName); 42 | Uri serviceUri = uriBuilder.Build(); 43 | 44 | // service may be partitioned. 45 | // this will aggregate the queue lengths from each partition 46 | ServicePartitionList partitions = await this.fabricClient.QueryManager.GetPartitionListAsync(serviceUri); 47 | 48 | long count = 0; 49 | foreach (Partition partition in partitions) 50 | { 51 | Uri getUrl = new HttpServiceUriBuilder() 52 | .SetServiceName(serviceUri) 53 | .SetPartitionKey(((Int64RangePartitionInformation) partition.PartitionInformation).LowKey) 54 | .SetServicePathAndQuery($"/api/devices/queue/length") 55 | .Build(); 56 | 57 | HttpResponseMessage response = await this.httpClient.GetAsync(getUrl, this.appLifetime.ApplicationStopping); 58 | 59 | if (response.StatusCode != System.Net.HttpStatusCode.OK) 60 | { 61 | return this.StatusCode((int) response.StatusCode); 62 | } 63 | 64 | string result = await response.Content.ReadAsStringAsync(); 65 | 66 | count += Int64.Parse(result); 67 | } 68 | 69 | return this.Ok(count); 70 | } 71 | 72 | [HttpGet] 73 | [Route("")] 74 | public async Task GetDevicesAsync() 75 | { 76 | ServiceUriBuilder uriBuilder = new ServiceUriBuilder(TenantDataServiceName); 77 | Uri serviceUri = uriBuilder.Build(); 78 | 79 | // service may be partitioned. 80 | // this will aggregate device IDs from all partitions 81 | ServicePartitionList partitions = await this.fabricClient.QueryManager.GetPartitionListAsync(serviceUri); 82 | 83 | List deviceViewModels = new List(); 84 | foreach (Partition partition in partitions) 85 | { 86 | Uri getUrl = new HttpServiceUriBuilder() 87 | .SetServiceName(serviceUri) 88 | .SetPartitionKey(((Int64RangePartitionInformation) partition.PartitionInformation).LowKey) 89 | .SetServicePathAndQuery($"/api/devices") 90 | .Build(); 91 | 92 | HttpResponseMessage response = await this.httpClient.GetAsync(getUrl, this.appLifetime.ApplicationStopping); 93 | 94 | if (response.StatusCode != System.Net.HttpStatusCode.OK) 95 | { 96 | return this.StatusCode((int) response.StatusCode); 97 | } 98 | 99 | JsonSerializer serializer = new JsonSerializer(); 100 | using (StreamReader streamReader = new StreamReader(await response.Content.ReadAsStreamAsync())) 101 | { 102 | using (JsonTextReader jsonReader = new JsonTextReader(streamReader)) 103 | { 104 | List result = serializer.Deserialize>(jsonReader); 105 | 106 | if (result != null) 107 | { 108 | deviceViewModels.AddRange(result); 109 | } 110 | } 111 | } 112 | } 113 | 114 | return this.Ok(deviceViewModels); 115 | } 116 | } 117 | } -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/Controllers/IngestionController.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Admin.WebService.Controllers 7 | { 8 | using Iot.Admin.WebService.Models; 9 | using Iot.Admin.WebService.ViewModels; 10 | using Iot.Common; 11 | using Microsoft.AspNetCore.Hosting; 12 | using Microsoft.AspNetCore.Mvc; 13 | using Microsoft.ServiceBus.Messaging; 14 | using System; 15 | using System.Collections.Specialized; 16 | using System.Fabric; 17 | using System.Fabric.Description; 18 | using System.Fabric.Query; 19 | using System.Linq; 20 | using System.Threading.Tasks; 21 | 22 | [Route("api/[Controller]")] 23 | public class IngestionController : Controller 24 | { 25 | private readonly TimeSpan operationTimeout = TimeSpan.FromSeconds(20); 26 | private readonly FabricClient fabricClient; 27 | private readonly IApplicationLifetime appLifetime; 28 | 29 | public IngestionController(FabricClient fabricClient, IApplicationLifetime appLifetime) 30 | { 31 | this.fabricClient = fabricClient; 32 | this.appLifetime = appLifetime; 33 | } 34 | 35 | [HttpGet] 36 | public async Task Get() 37 | { 38 | ApplicationList applications = await this.fabricClient.QueryManager.GetApplicationListAsync(); 39 | 40 | return this.Ok( 41 | applications 42 | .Where(x => x.ApplicationTypeName == Names.IngestionApplicationTypeName) 43 | .Select( 44 | x => 45 | new ApplicationViewModel( 46 | x.ApplicationName.ToString(), 47 | x.ApplicationStatus.ToString(), 48 | x.ApplicationTypeVersion, 49 | x.ApplicationParameters))); 50 | } 51 | 52 | [HttpPost] 53 | [Route("{name}")] 54 | public async Task Post([FromRoute] string name, [FromBody] IngestionApplicationParams parameters) 55 | { 56 | // Determine the number of IoT Hub partitions. 57 | // The ingestion service will be created with the same number of partitions. 58 | EventHubClient eventHubClient = EventHubClient.CreateFromConnectionString(parameters.IotHubConnectionString, "messages/events"); 59 | EventHubRuntimeInformation eventHubInfo = await eventHubClient.GetRuntimeInformationAsync(); 60 | 61 | // Application parameters are passed to the Ingestion application instance. 62 | NameValueCollection appInstanceParameters = new NameValueCollection(); 63 | appInstanceParameters["IotHubConnectionString"] = parameters.IotHubConnectionString; 64 | 65 | ApplicationDescription application = new ApplicationDescription( 66 | new Uri($"{Names.IngestionApplicationPrefix}/{name}"), 67 | Names.IngestionApplicationTypeName, 68 | parameters.Version, 69 | appInstanceParameters); 70 | 71 | // Create a named application instance 72 | await this.fabricClient.ApplicationManager.CreateApplicationAsync(application, this.operationTimeout, this.appLifetime.ApplicationStopping); 73 | 74 | // Next, create named instances of the services that run in the application. 75 | ServiceUriBuilder serviceNameUriBuilder = new ServiceUriBuilder(application.ApplicationName.ToString(), Names.IngestionRouterServiceName); 76 | 77 | StatefulServiceDescription service = new StatefulServiceDescription() 78 | { 79 | ApplicationName = application.ApplicationName, 80 | HasPersistedState = true, 81 | MinReplicaSetSize = 3, 82 | TargetReplicaSetSize = 3, 83 | PartitionSchemeDescription = new UniformInt64RangePartitionSchemeDescription(eventHubInfo.PartitionCount, 0, eventHubInfo.PartitionCount - 1), 84 | ServiceName = serviceNameUriBuilder.Build(), 85 | ServiceTypeName = Names.IngestionRouterServiceTypeName 86 | }; 87 | 88 | await this.fabricClient.ServiceManager.CreateServiceAsync(service, this.operationTimeout, this.appLifetime.ApplicationStopping); 89 | 90 | return this.Ok(); 91 | } 92 | 93 | [HttpDelete] 94 | [Route("{name}")] 95 | public async Task Delete(string name) 96 | { 97 | try 98 | { 99 | await this.fabricClient.ApplicationManager.DeleteApplicationAsync( 100 | new DeleteApplicationDescription(new Uri($"{Names.IngestionApplicationPrefix}/{name}")), 101 | this.operationTimeout, 102 | this.appLifetime.ApplicationStopping); 103 | } 104 | catch (FabricElementNotFoundException) 105 | { 106 | // service doesn't exist; nothing to delete 107 | } 108 | 109 | return this.Ok(); 110 | } 111 | } 112 | } -------------------------------------------------------------------------------- /src/Iot.Admin.WebService/Controllers/TenantsController.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Admin.WebService.Controllers 7 | { 8 | using Iot.Admin.WebService.Models; 9 | using Iot.Admin.WebService.ViewModels; 10 | using Iot.Common; 11 | using Microsoft.AspNetCore.Hosting; 12 | using Microsoft.AspNetCore.Mvc; 13 | using System; 14 | using System.Fabric; 15 | using System.Fabric.Description; 16 | using System.Fabric.Query; 17 | using System.Linq; 18 | using System.Threading.Tasks; 19 | 20 | [Route("api/[Controller]")] 21 | public class TenantsController : Controller 22 | { 23 | private readonly TimeSpan operationTimeout = TimeSpan.FromSeconds(20); 24 | private readonly FabricClient fabricClient; 25 | private readonly IApplicationLifetime appLifetime; 26 | 27 | public TenantsController(FabricClient fabricClient, IApplicationLifetime appLifetime) 28 | { 29 | this.fabricClient = fabricClient; 30 | this.appLifetime = appLifetime; 31 | } 32 | 33 | [HttpGet] 34 | public async Task Get() 35 | { 36 | ApplicationList applications = await this.fabricClient.QueryManager.GetApplicationListAsync(); 37 | 38 | return this.Ok( 39 | applications 40 | .Where(x => x.ApplicationTypeName == Names.TenantApplicationTypeName) 41 | .Select( 42 | x => 43 | new ApplicationViewModel( 44 | x.ApplicationName.ToString(), 45 | x.ApplicationStatus.ToString(), 46 | x.ApplicationTypeVersion, 47 | x.ApplicationParameters))); 48 | } 49 | 50 | [HttpPost] 51 | [Route("{tenantName}")] 52 | public async Task Post([FromRoute] string tenantName, [FromBody] TenantApplicationParams parameters) 53 | { 54 | // First create the application instance. 55 | // This won't actually create the services yet. 56 | ApplicationDescription application = new ApplicationDescription( 57 | new Uri($"{Names.TenantApplicationNamePrefix}/{tenantName}"), 58 | Names.TenantApplicationTypeName, 59 | parameters.Version); 60 | 61 | await this.fabricClient.ApplicationManager.CreateApplicationAsync(application, this.operationTimeout, this.appLifetime.ApplicationStopping); 62 | 63 | // Now create the data service in the new application instance. 64 | ServiceUriBuilder dataServiceNameUriBuilder = new ServiceUriBuilder(application.ApplicationName.ToString(), Names.TenantDataServiceName); 65 | StatefulServiceDescription dataServiceDescription = new StatefulServiceDescription() 66 | { 67 | ApplicationName = application.ApplicationName, 68 | HasPersistedState = true, 69 | MinReplicaSetSize = 3, 70 | TargetReplicaSetSize = 3, 71 | PartitionSchemeDescription = new UniformInt64RangePartitionSchemeDescription(parameters.DataPartitionCount, Int64.MinValue, Int64.MaxValue), 72 | ServiceName = dataServiceNameUriBuilder.Build(), 73 | ServiceTypeName = Names.TenantDataServiceTypeName 74 | }; 75 | 76 | await this.fabricClient.ServiceManager.CreateServiceAsync(dataServiceDescription, this.operationTimeout, this.appLifetime.ApplicationStopping); 77 | 78 | // And finally, create the web service in the new application instance. 79 | ServiceUriBuilder webServiceNameUriBuilder = new ServiceUriBuilder(application.ApplicationName.ToString(), Names.TenantWebServiceName); 80 | StatelessServiceDescription webServiceDescription = new StatelessServiceDescription() 81 | { 82 | ApplicationName = application.ApplicationName, 83 | InstanceCount = parameters.WebInstanceCount, 84 | PartitionSchemeDescription = new SingletonPartitionSchemeDescription(), 85 | ServiceName = webServiceNameUriBuilder.Build(), 86 | ServiceTypeName = Names.TenantWebServiceTypeName 87 | }; 88 | 89 | await this.fabricClient.ServiceManager.CreateServiceAsync(webServiceDescription, this.operationTimeout, this.appLifetime.ApplicationStopping); 90 | 91 | 92 | return this.Ok(); 93 | } 94 | 95 | [HttpDelete] 96 | [Route("{tenantName}")] 97 | public async Task Delete(string tenantName) 98 | { 99 | try 100 | { 101 | await this.fabricClient.ApplicationManager.DeleteApplicationAsync( 102 | new DeleteApplicationDescription(new Uri($"{Names.TenantApplicationNamePrefix}/{tenantName}")), 103 | this.operationTimeout, 104 | this.appLifetime.ApplicationStopping); 105 | } 106 | catch (FabricElementNotFoundException) 107 | { 108 | // service doesn't exist; nothing to delete 109 | } 110 | 111 | return this.Ok(); 112 | } 113 | } 114 | } -------------------------------------------------------------------------------- /src/Iot.Ingestion.RouterService/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /src/Iot.Mocks/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /src/Iot.Common/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /src/Iot.DeviceEmulator/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /src/Iot.Common/HttpServiceUriBuilder.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Common 7 | { 8 | using System; 9 | using System.Fabric; 10 | using System.Linq; 11 | using Microsoft.ServiceFabric.Services.Client; 12 | 13 | /// 14 | /// http://fabric/app/service/#/partitionkey/any|primary|secondary/endpoint-name/api-path 15 | /// 16 | public class HttpServiceUriBuilder 17 | { 18 | private const short FabricSchemeLength = 8; 19 | 20 | public HttpServiceUriBuilder() 21 | { 22 | this.Scheme = "http"; 23 | this.Host = "fabric"; 24 | this.Target = HttpServiceUriTarget.Default; 25 | } 26 | 27 | public HttpServiceUriBuilder(string uri) 28 | : this(new Uri(uri, UriKind.Absolute)) 29 | { 30 | } 31 | 32 | public HttpServiceUriBuilder(Uri uri) 33 | { 34 | this.Scheme = uri.Scheme; 35 | this.Host = uri.Host; 36 | this.ServiceName = new Uri("fabric:" + uri.AbsolutePath.TrimEnd('/')); 37 | 38 | string path = uri.Fragment.Remove(0, 2); 39 | string[] segments = path.Split('/'); 40 | 41 | long int64PartitionKey; 42 | this.PartitionKey = Int64.TryParse(segments[0], out int64PartitionKey) 43 | ? new ServicePartitionKey(int64PartitionKey) 44 | : String.IsNullOrEmpty(segments[0]) 45 | ? new ServicePartitionKey() 46 | : new ServicePartitionKey(segments[0]); 47 | 48 | HttpServiceUriTarget target; 49 | if (!Enum.TryParse(segments[1], true, out target)) 50 | { 51 | throw new ArgumentException(); 52 | } 53 | 54 | this.Target = target; 55 | this.EndpointName = segments[2]; 56 | this.ServicePathAndQuery = String.Join("/", segments.Skip(3)); 57 | } 58 | 59 | public string Scheme { get; private set; } 60 | 61 | public string Host { get; private set; } 62 | 63 | public Uri ServiceName { get; private set; } 64 | 65 | public ServicePartitionKey PartitionKey { get; private set; } 66 | 67 | public HttpServiceUriTarget Target { get; private set; } 68 | 69 | public string EndpointName { get; private set; } 70 | 71 | public string ServicePathAndQuery { get; private set; } 72 | 73 | public override string ToString() 74 | { 75 | return base.ToString(); 76 | } 77 | 78 | public Uri Build() 79 | { 80 | if (this.ServiceName == null) 81 | { 82 | throw new UriFormatException("Service name is null."); 83 | } 84 | 85 | UriBuilder builder = new UriBuilder(); 86 | builder.Scheme = String.IsNullOrEmpty(this.Scheme) ? "http" : this.Scheme; 87 | builder.Host = String.IsNullOrEmpty(this.Host) ? "fabric" : this.Host; 88 | builder.Path = this.ServiceName.AbsolutePath.Trim('/') + '/'; 89 | ; 90 | string partitionKey = this.PartitionKey == null || this.PartitionKey.Kind == ServicePartitionKind.Singleton 91 | ? String.Empty 92 | : this.PartitionKey.Value.ToString(); 93 | 94 | builder.Fragment = $"/{partitionKey}/{this.Target.ToString()}/{this.EndpointName ?? String.Empty}/{this.ServicePathAndQuery ?? String.Empty}"; 95 | 96 | return builder.Uri; 97 | } 98 | 99 | public HttpServiceUriBuilder SetHost(string host) 100 | { 101 | this.Host = host?.ToLowerInvariant(); 102 | return this; 103 | } 104 | 105 | public HttpServiceUriBuilder SetScheme(string scheme) 106 | { 107 | this.Scheme = scheme?.ToLowerInvariant(); 108 | return this; 109 | } 110 | 111 | /// 112 | /// Fully-qualified service name URI: fabric:/name/of/service 113 | /// 114 | /// 115 | /// 116 | public HttpServiceUriBuilder SetServiceName(Uri serviceName) 117 | { 118 | if (serviceName != null) 119 | { 120 | if (!serviceName.IsAbsoluteUri) 121 | { 122 | throw new UriFormatException("Service URI must be an absolute URI in the form 'fabric:/name/of/service"); 123 | } 124 | 125 | if (!String.Equals(serviceName.Scheme, "fabric", StringComparison.OrdinalIgnoreCase)) 126 | { 127 | throw new UriFormatException("Scheme must be 'fabric'."); 128 | } 129 | } 130 | 131 | this.ServiceName = serviceName; 132 | 133 | return this; 134 | } 135 | 136 | /// 137 | /// Fully-qualified service name URI: fabric:/name/of/service 138 | /// 139 | /// 140 | /// 141 | public HttpServiceUriBuilder SetServiceName(string serviceName) 142 | { 143 | return this.SetServiceName(new Uri(serviceName, UriKind.Absolute)); 144 | } 145 | 146 | public HttpServiceUriBuilder SetPartitionKey(string namedPartitionKey) 147 | { 148 | this.PartitionKey = new ServicePartitionKey(namedPartitionKey); 149 | return this; 150 | } 151 | 152 | public HttpServiceUriBuilder SetPartitionKey(long int64PartitionKey) 153 | { 154 | this.PartitionKey = new ServicePartitionKey(int64PartitionKey); 155 | return this; 156 | } 157 | 158 | public HttpServiceUriBuilder SetTarget(HttpServiceUriTarget target) 159 | { 160 | this.Target = target; 161 | return this; 162 | } 163 | 164 | public HttpServiceUriBuilder SetEndpointName(string endpointName) 165 | { 166 | this.EndpointName = endpointName; 167 | return this; 168 | } 169 | 170 | public HttpServiceUriBuilder SetServicePathAndQuery(string servicePathAndQuery) 171 | { 172 | this.ServicePathAndQuery = servicePathAndQuery; 173 | return this; 174 | } 175 | } 176 | } -------------------------------------------------------------------------------- /src/Iot.Mocks/MockCodePackageActivationContext.cs: -------------------------------------------------------------------------------- 1 | namespace Iot.Mocks 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Collections.ObjectModel; 6 | using System.Fabric; 7 | using System.Fabric.Description; 8 | using System.Fabric.Health; 9 | 10 | public class MockCodePackageActivationContext : ICodePackageActivationContext 11 | { 12 | public string ApplicationName { get; private set; } 13 | 14 | public string ApplicationTypeName { get; private set; } 15 | 16 | public string CodePackageName { get; private set; } 17 | 18 | public string CodePackageVersion { get; private set; } 19 | 20 | public string ContextId { get; private set; } 21 | 22 | public string LogDirectory { get; private set; } 23 | 24 | public string TempDirectory { get; private set; } 25 | 26 | public string WorkDirectory { get; private set; } 27 | private string ServiceManifetName { get; set; } 28 | 29 | private string ServiceManifestVersion { get; set; } 30 | 31 | 32 | public event EventHandler> CodePackageAddedEvent; 33 | public event EventHandler> CodePackageModifiedEvent; 34 | public event EventHandler> CodePackageRemovedEvent; 35 | public event EventHandler> ConfigurationPackageAddedEvent; 36 | public event EventHandler> ConfigurationPackageModifiedEvent; 37 | public event EventHandler> ConfigurationPackageRemovedEvent; 38 | public event EventHandler> DataPackageAddedEvent; 39 | public event EventHandler> DataPackageModifiedEvent; 40 | public event EventHandler> DataPackageRemovedEvent; 41 | 42 | public ApplicationPrincipalsDescription GetApplicationPrincipals() 43 | { 44 | throw new NotImplementedException(); 45 | } 46 | 47 | public IList GetCodePackageNames() 48 | { 49 | return new List() { this.CodePackageName }; 50 | } 51 | 52 | public CodePackage GetCodePackageObject(string packageName) 53 | { 54 | throw new NotImplementedException(); 55 | } 56 | 57 | public IList GetConfigurationPackageNames() 58 | { 59 | return new List() { "" }; 60 | } 61 | 62 | public ConfigurationPackage GetConfigurationPackageObject(string packageName) 63 | { 64 | throw new NotImplementedException(); 65 | } 66 | 67 | public IList GetDataPackageNames() 68 | { 69 | return new List() { "" }; 70 | } 71 | 72 | public DataPackage GetDataPackageObject(string packageName) 73 | { 74 | throw new NotImplementedException(); 75 | } 76 | 77 | public EndpointResourceDescription GetEndpoint(string endpointName) 78 | { 79 | throw new NotImplementedException(); 80 | } 81 | 82 | public KeyedCollection GetEndpoints() 83 | { 84 | throw new NotImplementedException(); 85 | } 86 | 87 | public KeyedCollection GetServiceGroupTypes() 88 | { 89 | throw new NotImplementedException(); 90 | } 91 | 92 | public string GetServiceManifestName() 93 | { 94 | return this.ServiceManifetName; 95 | } 96 | 97 | public string GetServiceManifestVersion() 98 | { 99 | return this.ServiceManifestVersion; 100 | } 101 | 102 | public KeyedCollection GetServiceTypes() 103 | { 104 | throw new NotImplementedException(); 105 | } 106 | 107 | public void ReportApplicationHealth(HealthInformation healthInformation) 108 | { 109 | throw new NotImplementedException(); 110 | } 111 | 112 | public void ReportDeployedServicePackageHealth(HealthInformation healthInformation) 113 | { 114 | throw new NotImplementedException(); 115 | } 116 | 117 | public void ReportDeployedApplicationHealth(HealthInformation healthInformation) 118 | { 119 | throw new NotImplementedException(); 120 | } 121 | 122 | 123 | 124 | public MockCodePackageActivationContext( 125 | string ApplicationName, 126 | string ApplicationTypeName, 127 | string CodePackageName, 128 | string CodePackageVersion, 129 | string Context, 130 | string LogDirectory, 131 | string TempDirectory, 132 | string WorkDirectory, 133 | string ServiceManifestName, 134 | string ServiceManifestVersion) 135 | { 136 | 137 | this.ApplicationName = ApplicationName; 138 | this.ApplicationTypeName = ApplicationTypeName; 139 | this.CodePackageName = CodePackageName; 140 | this.CodePackageVersion = CodePackageVersion; 141 | this.ContextId = Context; 142 | this.LogDirectory = LogDirectory; 143 | this.TempDirectory = TempDirectory; 144 | this.WorkDirectory = WorkDirectory; 145 | } 146 | 147 | 148 | #region IDisposable Support 149 | private bool disposedValue = false; // To detect redundant calls 150 | 151 | protected virtual void Dispose(bool disposing) 152 | { 153 | if (!disposedValue) 154 | { 155 | if (disposing) 156 | { 157 | // TODO: dispose managed state (managed objects). 158 | } 159 | 160 | // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below. 161 | // TODO: set large fields to null. 162 | 163 | disposedValue = true; 164 | } 165 | } 166 | 167 | // This code added to correctly implement the disposable pattern. 168 | public void Dispose() 169 | { 170 | // Do not change this code. Put cleanup code in Dispose(bool disposing) above. 171 | Dispose(true); 172 | // TODO: uncomment the following line if the finalizer is overridden above. 173 | // GC.SuppressFinalize(this); 174 | } 175 | #endregion 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /src/Iot.Tenant.DataService/DataService.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Iot.Tenant.DataService 7 | { 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Fabric; 11 | using System.IO; 12 | using System.Threading; 13 | using System.Threading.Tasks; 14 | using Iot.Tenant.DataService.Models; 15 | using Microsoft.AspNetCore.Hosting; 16 | using Microsoft.Extensions.DependencyInjection; 17 | using Microsoft.ServiceFabric.Data; 18 | using Microsoft.ServiceFabric.Data.Collections; 19 | using Microsoft.ServiceFabric.Services.Communication.Runtime; 20 | using Microsoft.ServiceFabric.Services.Runtime; 21 | using Common; 22 | using Microsoft.ServiceFabric.Services.Communication.AspNetCore; 23 | 24 | internal sealed class DataService : StatefulService 25 | { 26 | internal const string EventDictionaryName = "store://events/dictionary"; 27 | internal const string EventQueueName = "store://events/queue"; 28 | private const int OffloadBatchSize = 100; 29 | private const int DrainIteration = 5; 30 | private readonly TimeSpan OffloadBatchInterval = TimeSpan.FromSeconds(10); 31 | 32 | 33 | public DataService(StatefulServiceContext context) 34 | : base(context) 35 | { 36 | } 37 | 38 | protected override IEnumerable CreateServiceReplicaListeners() 39 | { 40 | return new ServiceReplicaListener[1] 41 | { 42 | new ServiceReplicaListener( 43 | context => 44 | new KestrelCommunicationListener( 45 | context, 46 | (url, listener) => 47 | { 48 | ServiceEventSource.Current.Message($"Listening on {url}"); 49 | 50 | return new WebHostBuilder() 51 | .UseKestrel() 52 | .ConfigureServices( 53 | services => services 54 | .AddSingleton(this.Context) 55 | .AddSingleton(this.StateManager)) 56 | .UseContentRoot(Directory.GetCurrentDirectory()) 57 | .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.UseUniqueServiceUrl) 58 | .UseStartup() 59 | .UseUrls(url) 60 | .Build(); 61 | }) 62 | ) 63 | }; 64 | } 65 | 66 | protected override async Task RunAsync(CancellationToken cancellationToken) 67 | { 68 | IReliableQueue queue = await this.StateManager.GetOrAddAsync>(EventQueueName); 69 | 70 | int iteration = 0; 71 | while(true) 72 | { 73 | cancellationToken.ThrowIfCancellationRequested(); 74 | 75 | try 76 | { 77 | using (ITransaction tx = this.StateManager.CreateTransaction()) 78 | { 79 | // When the number of items in the queue reaches a certain size.. 80 | int count = (int) await queue.GetCountAsync(tx); 81 | 82 | ServiceEventSource.Current.ServiceMessage( 83 | this.Context, 84 | "Current queue size: {0} in iteration {1}", 85 | count, iteration); 86 | 87 | // if the queue size reaches the batch size, start draining the queue 88 | // always drain the queue every nth iteration so that nothing sits in the queue indefinitely 89 | if (count >= OffloadBatchSize || iteration == DrainIteration) 90 | { 91 | ServiceEventSource.Current.ServiceMessage( 92 | this.Context, 93 | "Starting batch offload.."); 94 | 95 | // Dequeue the items into a batch 96 | List batch = new List(count); 97 | 98 | for (int i = 0; i < count; ++i) 99 | { 100 | cancellationToken.ThrowIfCancellationRequested(); 101 | 102 | ConditionalValue result = await queue.TryDequeueAsync(tx); 103 | 104 | if (result.HasValue) 105 | { 106 | batch.Add(result.Value); 107 | } 108 | } 109 | 110 | //TODO: Process the data or send to a storage location. 111 | 112 | // Commit the dequeue operations 113 | await tx.CommitAsync(); 114 | 115 | ServiceEventSource.Current.ServiceMessage( 116 | this.Context, 117 | "Batch offloaded {0} events.", 118 | count); 119 | 120 | // skip the delay and move on to the next batch. 121 | iteration = 0; 122 | continue; 123 | } 124 | else if (count > 0) 125 | { 126 | iteration++; 127 | } 128 | } 129 | } 130 | catch (TimeoutException) 131 | { 132 | // transient error. Retry. 133 | ServiceEventSource.Current.ServiceMessage(this.Context, "TimeoutException in RunAsync."); 134 | } 135 | catch (FabricTransientException fte) 136 | { 137 | // transient error. Retry. 138 | ServiceEventSource.Current.ServiceMessage(this.Context, "FabricTransientException in RunAsync: {0}", fte.Message); 139 | } 140 | catch (FabricNotPrimaryException) 141 | { 142 | // not primary any more, time to quit. 143 | return; 144 | } 145 | 146 | await Task.Delay(this.OffloadBatchInterval, cancellationToken); 147 | } 148 | } 149 | } 150 | } --------------------------------------------------------------------------------