├── 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 |
7 |
8 |
9 |
10 |
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 |
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 |
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 | }
--------------------------------------------------------------------------------