diff --git a/.github/workflows/ci-dotnet.yml b/.github/workflows/ci-dotnet.yml index 49014d5d12..4ba7449014 100644 --- a/.github/workflows/ci-dotnet.yml +++ b/.github/workflows/ci-dotnet.yml @@ -77,8 +77,7 @@ jobs: - name: Install .NET connector templates run: | - dotnet new install dotnet/templates/EventDrivenTelemetryConnector - dotnet new install dotnet/templates/PollingTelemetryConnector + dotnet new install dotnet/templates - name: Build Faultable MQTT Broker run: dotnet build eng/test/faultablemqttbroker/src/Azure.Iot.Operations.FaultableMqttBroker/Azure.Iot.Operations.FaultableMqttBroker.csproj diff --git a/dotnet/Azure.Iot.Operations.sln b/dotnet/Azure.Iot.Operations.sln index 08731dcfeb..bb3c80ff6d 100644 --- a/dotnet/Azure.Iot.Operations.sln +++ b/dotnet/Azure.Iot.Operations.sln @@ -75,8 +75,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SqlQualityAnalyzerConnector EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Connectors", "Connectors", "{78562762-96CB-4527-8EE2-43A1CE119A21}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventDrivenTelemetryConnector", "templates\EventDrivenTelemetryConnector\EventDrivenTelemetryConnector.csproj", "{A05529AD-2D62-405A-9C2D-A122F837ECBD}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PollingRestThermostatConnector", "samples\Connectors\PollingRestThermostatConnector\PollingRestThermostatConnector.csproj", "{6D8CEBB2-C805-4B45-AAFB-418B1E558146}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleTcpServiceApp", "samples\Connectors\SampleTcpServiceApp\SampleTcpServiceApp.csproj", "{566859E0-8783-92AF-29D8-F8C23A802B45}" @@ -87,7 +85,17 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StateChangeSample", "sample EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Iot.Operations.Connector.IntegrationTests", "test\Azure.Iot.Operations.Connector.IntegrationTests\Azure.Iot.Operations.Connector.IntegrationTests.csproj", "{C527ECCE-FBE1-4FBC-9987-F94BACC904F2}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PollingTelemetryConnectorTemplate", "templates\PollingTelemetryConnector\PollingTelemetryConnectorTemplate.csproj", "{698D0245-18C6-37E9-08F6-E8EADCBA0880}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Iot.Operations.Templates", "templates\Azure.Iot.Operations.Templates.csproj", "{997B55FE-157D-4EF8-8F56-94A828C9F464}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "content", "content", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EventDrivenTelemetryConnector", "EventDrivenTelemetryConnector", "{4117C707-7647-4CB7-9933-A00D7730664C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PollingTelemetryConnector", "PollingTelemetryConnector", "{8826F302-A3F9-4543-90EE-27196D9179EA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Iot.Operations.Templates.EventDrivenConnectorTemplate", "templates\content\EventDrivenConnectorTemplate\Azure.Iot.Operations.Templates.EventDrivenConnectorTemplate.csproj", "{ADDAE3BF-371C-4D4C-913E-9D165F28D6F2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Iot.Operations.Templates.PollingConnectorTemplate", "templates\content\PollingConnectorTemplate\Azure.Iot.Operations.Templates.PollingConnectorTemplate.csproj", "{2D62BB36-B1A0-4A57-9F13-EA37A6E6FD51}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -199,10 +207,6 @@ Global {C75E1DD5-0E63-43CB-A16E-6829231059C1}.Debug|Any CPU.Build.0 = Debug|Any CPU {C75E1DD5-0E63-43CB-A16E-6829231059C1}.Release|Any CPU.ActiveCfg = Release|Any CPU {C75E1DD5-0E63-43CB-A16E-6829231059C1}.Release|Any CPU.Build.0 = Release|Any CPU - {A05529AD-2D62-405A-9C2D-A122F837ECBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A05529AD-2D62-405A-9C2D-A122F837ECBD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A05529AD-2D62-405A-9C2D-A122F837ECBD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A05529AD-2D62-405A-9C2D-A122F837ECBD}.Release|Any CPU.Build.0 = Release|Any CPU {6D8CEBB2-C805-4B45-AAFB-418B1E558146}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6D8CEBB2-C805-4B45-AAFB-418B1E558146}.Debug|Any CPU.Build.0 = Debug|Any CPU {6D8CEBB2-C805-4B45-AAFB-418B1E558146}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -223,10 +227,18 @@ Global {C527ECCE-FBE1-4FBC-9987-F94BACC904F2}.Debug|Any CPU.Build.0 = Debug|Any CPU {C527ECCE-FBE1-4FBC-9987-F94BACC904F2}.Release|Any CPU.ActiveCfg = Release|Any CPU {C527ECCE-FBE1-4FBC-9987-F94BACC904F2}.Release|Any CPU.Build.0 = Release|Any CPU - {698D0245-18C6-37E9-08F6-E8EADCBA0880}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {698D0245-18C6-37E9-08F6-E8EADCBA0880}.Debug|Any CPU.Build.0 = Debug|Any CPU - {698D0245-18C6-37E9-08F6-E8EADCBA0880}.Release|Any CPU.ActiveCfg = Release|Any CPU - {698D0245-18C6-37E9-08F6-E8EADCBA0880}.Release|Any CPU.Build.0 = Release|Any CPU + {997B55FE-157D-4EF8-8F56-94A828C9F464}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {997B55FE-157D-4EF8-8F56-94A828C9F464}.Debug|Any CPU.Build.0 = Debug|Any CPU + {997B55FE-157D-4EF8-8F56-94A828C9F464}.Release|Any CPU.ActiveCfg = Release|Any CPU + {997B55FE-157D-4EF8-8F56-94A828C9F464}.Release|Any CPU.Build.0 = Release|Any CPU + {ADDAE3BF-371C-4D4C-913E-9D165F28D6F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ADDAE3BF-371C-4D4C-913E-9D165F28D6F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ADDAE3BF-371C-4D4C-913E-9D165F28D6F2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ADDAE3BF-371C-4D4C-913E-9D165F28D6F2}.Release|Any CPU.Build.0 = Release|Any CPU + {2D62BB36-B1A0-4A57-9F13-EA37A6E6FD51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2D62BB36-B1A0-4A57-9F13-EA37A6E6FD51}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2D62BB36-B1A0-4A57-9F13-EA37A6E6FD51}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2D62BB36-B1A0-4A57-9F13-EA37A6E6FD51}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -263,13 +275,17 @@ Global {99113A50-9774-4F42-B18D-5284639194A6} = {CE9A7664-594B-43EB-AA48-606B88411FC9} {C75E1DD5-0E63-43CB-A16E-6829231059C1} = {78562762-96CB-4527-8EE2-43A1CE119A21} {78562762-96CB-4527-8EE2-43A1CE119A21} = {9126F576-80AE-48DC-8A84-EFC8B487D809} - {A05529AD-2D62-405A-9C2D-A122F837ECBD} = {4636D1F8-ACA6-4138-8EC0-1FF71CAF3A3B} {6D8CEBB2-C805-4B45-AAFB-418B1E558146} = {78562762-96CB-4527-8EE2-43A1CE119A21} {566859E0-8783-92AF-29D8-F8C23A802B45} = {78562762-96CB-4527-8EE2-43A1CE119A21} {E97EAFE6-F4D8-4B9A-B53C-8A479A9BBFB5} = {78562762-96CB-4527-8EE2-43A1CE119A21} {4992415C-ABB2-2284-D6CD-8FE01910092F} = {4DDB0B28-1830-4B6F-8A10-FB37874D4D57} {C527ECCE-FBE1-4FBC-9987-F94BACC904F2} = {CE9A7664-594B-43EB-AA48-606B88411FC9} - {698D0245-18C6-37E9-08F6-E8EADCBA0880} = {4636D1F8-ACA6-4138-8EC0-1FF71CAF3A3B} + {997B55FE-157D-4EF8-8F56-94A828C9F464} = {4636D1F8-ACA6-4138-8EC0-1FF71CAF3A3B} + {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {4636D1F8-ACA6-4138-8EC0-1FF71CAF3A3B} + {4117C707-7647-4CB7-9933-A00D7730664C} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {8826F302-A3F9-4543-90EE-27196D9179EA} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {ADDAE3BF-371C-4D4C-913E-9D165F28D6F2} = {4117C707-7647-4CB7-9933-A00D7730664C} + {2D62BB36-B1A0-4A57-9F13-EA37A6E6FD51} = {8826F302-A3F9-4543-90EE-27196D9179EA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {F2687BCD-45E3-4094-9656-BF183C816BA0} diff --git a/dotnet/templates/Azure.Iot.Operations.Templates.csproj b/dotnet/templates/Azure.Iot.Operations.Templates.csproj new file mode 100644 index 0000000000..48700f723f --- /dev/null +++ b/dotnet/templates/Azure.Iot.Operations.Templates.csproj @@ -0,0 +1,42 @@ + + + + Azure.Iot.Operations.Templates + 0.1.0 + Azure IoT Operations Templates + Microsoft + .NET project templates for creating Azure IoT Operations solutions + azure;iot;sdk;edge + https://github.com/Azure/iot-operations-sdks/ + https://github.com/Azure/iot-operations-sdks/blob/main/LICENSE + MIT + © Microsoft Corporation. All rights reserved. + + Template + net9.0 + true + false + content + $(NoWarn);NU5128 + true + README.md + + + + false + + + + + + + + + + + + + + + + diff --git a/dotnet/templates/EventDrivenTelemetryConnector/LeaderElectionConfigurationProvider.cs b/dotnet/templates/EventDrivenTelemetryConnector/LeaderElectionConfigurationProvider.cs deleted file mode 100644 index 54e383d4d1..0000000000 --- a/dotnet/templates/EventDrivenTelemetryConnector/LeaderElectionConfigurationProvider.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using Azure.Iot.Operations.Connector; - -namespace EventDrivenTelemetryConnector -{ - public class LeaderElectionConfigurationProvider : IConnectorLeaderElectionConfigurationProvider - { - public static Func Factory = service => - { - return new LeaderElectionConfigurationProvider(); - }; - - public ConnectorLeaderElectionConfiguration GetLeaderElectionConfiguration() - { - return new("some-http-leadership-position-id", TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(9)); - } - } -} diff --git a/dotnet/templates/PollingTelemetryConnector/LeaderElectionConfigurationProvider.cs b/dotnet/templates/PollingTelemetryConnector/LeaderElectionConfigurationProvider.cs deleted file mode 100644 index 0d1f47c37a..0000000000 --- a/dotnet/templates/PollingTelemetryConnector/LeaderElectionConfigurationProvider.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using Azure.Iot.Operations.Connector; - -namespace PollingTelemetryConnectorTemplate -{ - public class LeaderElectionConfigurationProvider : IConnectorLeaderElectionConfigurationProvider - { - public static Func Factory = service => - { - return new LeaderElectionConfigurationProvider(); - }; - - public ConnectorLeaderElectionConfiguration GetLeaderElectionConfiguration() - { - return new("some-http-leadership-position-id", TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(9)); - } - } -} diff --git a/dotnet/templates/README.md b/dotnet/templates/README.md index 38ae9361ea..97e9f1f432 100644 --- a/dotnet/templates/README.md +++ b/dotnet/templates/README.md @@ -1,11 +1,26 @@ -# Azure IoT Operation .NET Project Templates +# Azure IoT Operations .NET Project Templates -This folder contains .NET project tempate definitions that are useful when developing -applications for your Azure IoT Operations environment. +This package contains the following project templates to help you develop Azure IoT Operations solutions: + + - Azure.Iot.Operations.Templates.PollingConnectorTemplate + - A template for creating an AIO connector that polls an endpoint and forwards that polled telemetry to the AIO MQTT broker. + - Azure.Iot.Operations.Templates.EventDrivenConnectorTemplate + - A template for creating an AIO connector that listens for events from an endpoint and forwards those events the AIO MQTT broker as telemetry. + + +For examples on how to fill out these templates, see the completed samples [here](https://github.com/Azure/iot-operations-sdks/tree/main/dotnet/samples). + +If you have any questions or need any support, please file an issue [here](https://github.com/Azure/iot-operations-sdks/issues) ## How To Install A .NET Project Template -To install a project template, simply navigate to the directory of the template you want to install and run the command: +To install these templates using the published package in Nuget.org, run the following command: + +```bash +dotnet new install Azure.Iot.Operations.Template +``` + +Alternatively, to install these templates from source, run the following command in this directory: ```bash dotnet new install . @@ -23,14 +38,20 @@ Alternatively, you can create a new project from an installed template from comm dotnet new aiopollingtelemetryconnector -n MyConnectorApp ``` -Where "aiopollingtelemetryconnector" is the short name defined in the project template's [template.json file](./PollingTelemetryConnector/.template.config/template.json) and where "MyConnectorApp" is the name of your project. +Where "aiopollingtelemetryconnector" is the short name defined in the project template's [template.json file](./content/PollingConnectorTemplate/.template.config/template.json) and where "MyConnectorApp" is the name of your project. Note that this command will create the project "MyConnectorApp" in the same directory that the command was run from. ## How To Uninstall A .NET Project Template -Navigate to the directory with the project template to uninstall and run the command: +To uninstall these templates when they were installed from the published package in Nuget.org, run the following command: ```bash -dotnet new uninstall . +dotnet new uninstall Azure.Iot.Operations.Template ``` + +Alternatively, to uninstall these templates when they were installed from source, run the following command in this directory: + +```bash +dotnet new uninstall . +``` \ No newline at end of file diff --git a/dotnet/templates/EventDrivenTelemetryConnector/.template.config/template.json b/dotnet/templates/content/EventDrivenConnectorTemplate/.template.config/template.json similarity index 83% rename from dotnet/templates/EventDrivenTelemetryConnector/.template.config/template.json rename to dotnet/templates/content/EventDrivenConnectorTemplate/.template.config/template.json index 70d6b54c9a..997081d551 100644 --- a/dotnet/templates/EventDrivenTelemetryConnector/.template.config/template.json +++ b/dotnet/templates/content/EventDrivenConnectorTemplate/.template.config/template.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/template", "author": "timtay-microsoft", "classifications": [ "Linux", "Windows", "Service"], - "identity": "AzureIotOperations.EventDrivenTelemetryConnector", + "identity": "Azure.Iot.Operations.Templates.EventDrivenConnectorTemplate", "name": "Azure IoT Operations Event Driven Telemetry Connector", "shortName": "aioeventdriventelemetryconnector", "sourceName":"EventDrivenTelemetryConnector", diff --git a/dotnet/templates/PollingTelemetryConnector/PollingTelemetryConnectorTemplate.csproj b/dotnet/templates/content/EventDrivenConnectorTemplate/Azure.Iot.Operations.Templates.EventDrivenConnectorTemplate.csproj similarity index 84% rename from dotnet/templates/PollingTelemetryConnector/PollingTelemetryConnectorTemplate.csproj rename to dotnet/templates/content/EventDrivenConnectorTemplate/Azure.Iot.Operations.Templates.EventDrivenConnectorTemplate.csproj index 96bb591866..65119de126 100644 --- a/dotnet/templates/PollingTelemetryConnector/PollingTelemetryConnectorTemplate.csproj +++ b/dotnet/templates/content/EventDrivenConnectorTemplate/Azure.Iot.Operations.Templates.EventDrivenConnectorTemplate.csproj @@ -1,4 +1,4 @@ - + net9.0 @@ -9,6 +9,6 @@ - + diff --git a/dotnet/templates/content/EventDrivenConnectorTemplate/LeaderElectionConfigurationProvider.cs b/dotnet/templates/content/EventDrivenConnectorTemplate/LeaderElectionConfigurationProvider.cs new file mode 100644 index 0000000000..e39cdc3d6a --- /dev/null +++ b/dotnet/templates/content/EventDrivenConnectorTemplate/LeaderElectionConfigurationProvider.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Azure.Iot.Operations.Connector; + +namespace EventDrivenTelemetryConnector +{ + /// + /// Factory that provides all leader election configurations for this connector. + /// + /// + /// Connectors can have active/passive replication by deploying more than one replica and having each replica + /// provide the same leadership position Id. That way, only one replica is the leader at a time. + /// + /// If no replication of this connector is needed, then this class can be deleted. + /// + public class LeaderElectionConfigurationProvider : IConnectorLeaderElectionConfigurationProvider + { + public static Func Factory = service => + { + return new LeaderElectionConfigurationProvider(); + }; + + public ConnectorLeaderElectionConfiguration GetLeaderElectionConfiguration() + { + // This value should be the same across any replicas but should be unique from connector to connector. + string leadershipPositionId = "some-leadership-position-id"; + return new(leadershipPositionId, TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(9)); + } + } +} diff --git a/dotnet/templates/EventDrivenTelemetryConnector/MessageSchemaProvider.cs b/dotnet/templates/content/EventDrivenConnectorTemplate/MessageSchemaProvider.cs similarity index 68% rename from dotnet/templates/EventDrivenTelemetryConnector/MessageSchemaProvider.cs rename to dotnet/templates/content/EventDrivenConnectorTemplate/MessageSchemaProvider.cs index 640bfb4483..93e1434642 100644 --- a/dotnet/templates/EventDrivenTelemetryConnector/MessageSchemaProvider.cs +++ b/dotnet/templates/content/EventDrivenConnectorTemplate/MessageSchemaProvider.cs @@ -6,6 +6,15 @@ namespace EventDrivenTelemetryConnector { + /// + /// The factory method for determining what message schema should be registered for and attached to each + /// emitted telemetry message for each event handled by this connector. If no message schema is needed, + /// then this class can be left as-is. + /// + /// + /// Registering message schemas allows the receiver of a message to fetch this schema from the schema + /// registry service. With that schema, the receiver can correctly deserialize each received message's payload. + /// internal class MessageSchemaProvider : IMessageSchemaProvider { public static Func Factory = service => diff --git a/dotnet/templates/EventDrivenTelemetryConnector/Program.cs b/dotnet/templates/content/EventDrivenConnectorTemplate/Program.cs similarity index 74% rename from dotnet/templates/EventDrivenTelemetryConnector/Program.cs rename to dotnet/templates/content/EventDrivenConnectorTemplate/Program.cs index 8202d139e4..82b3caad0b 100644 --- a/dotnet/templates/EventDrivenTelemetryConnector/Program.cs +++ b/dotnet/templates/content/EventDrivenConnectorTemplate/Program.cs @@ -2,12 +2,9 @@ // Licensed under the MIT License. using Azure.Iot.Operations.Connector; -using Azure.Iot.Operations.Connector.ConnectorConfigurations; using Azure.Iot.Operations.Protocol; using EventDrivenTelemetryConnector; -string connectorClientId = Environment.GetEnvironmentVariable(ConnectorFileMountSettings.ConnectorClientIdEnvVar) ?? throw new InvalidOperationException("No MQTT client Id configured by Akri operator"); - IHost host = Host.CreateDefaultBuilder(args) .ConfigureServices(services => { diff --git a/dotnet/templates/EventDrivenTelemetryConnector/TemplateConnectorWorker.cs b/dotnet/templates/content/EventDrivenConnectorTemplate/TemplateConnectorWorker.cs similarity index 100% rename from dotnet/templates/EventDrivenTelemetryConnector/TemplateConnectorWorker.cs rename to dotnet/templates/content/EventDrivenConnectorTemplate/TemplateConnectorWorker.cs diff --git a/dotnet/templates/content/EventDrivenConnectorTemplate/Worker.cs b/dotnet/templates/content/EventDrivenConnectorTemplate/Worker.cs new file mode 100644 index 0000000000..e140dc4403 --- /dev/null +++ b/dotnet/templates/content/EventDrivenConnectorTemplate/Worker.cs @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace EventDrivenConnectorTemplate +{ + public class Worker : BackgroundService + { + private readonly ILogger _logger; + + public Worker(ILogger logger) + { + _logger = logger; + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + while (!stoppingToken.IsCancellationRequested) + { + if (_logger.IsEnabled(LogLevel.Information)) + { + _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now); + } + await Task.Delay(1000, stoppingToken); + } + } + } +} diff --git a/dotnet/templates/EventDrivenTelemetryConnector/appsettings.Development.json b/dotnet/templates/content/EventDrivenConnectorTemplate/appsettings.Development.json similarity index 100% rename from dotnet/templates/EventDrivenTelemetryConnector/appsettings.Development.json rename to dotnet/templates/content/EventDrivenConnectorTemplate/appsettings.Development.json diff --git a/dotnet/templates/EventDrivenTelemetryConnector/appsettings.json b/dotnet/templates/content/EventDrivenConnectorTemplate/appsettings.json similarity index 100% rename from dotnet/templates/EventDrivenTelemetryConnector/appsettings.json rename to dotnet/templates/content/EventDrivenConnectorTemplate/appsettings.json diff --git a/dotnet/templates/PollingTelemetryConnector/.template.config/template.json b/dotnet/templates/content/PollingConnectorTemplate/.template.config/template.json similarity index 83% rename from dotnet/templates/PollingTelemetryConnector/.template.config/template.json rename to dotnet/templates/content/PollingConnectorTemplate/.template.config/template.json index 2fa8beb702..0408c72e8d 100644 --- a/dotnet/templates/PollingTelemetryConnector/.template.config/template.json +++ b/dotnet/templates/content/PollingConnectorTemplate/.template.config/template.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/template", "author": "timtay-microsoft", "classifications": [ "Linux", "Windows", "Service"], - "identity": "AzureIotOperations.PollingTelemetryConnector", + "identity": "Azure.Iot.Operations.Templates.PollingConnectorTemplate", "name": "Azure IoT Operations Polling Telemetry Connector", "shortName": "aiopollingtelemetryconnector", "sourceName":"PollingTelemetryConnectorTemplate", diff --git a/dotnet/templates/EventDrivenTelemetryConnector/EventDrivenTelemetryConnector.csproj b/dotnet/templates/content/PollingConnectorTemplate/Azure.Iot.Operations.Templates.PollingConnectorTemplate.csproj similarity index 84% rename from dotnet/templates/EventDrivenTelemetryConnector/EventDrivenTelemetryConnector.csproj rename to dotnet/templates/content/PollingConnectorTemplate/Azure.Iot.Operations.Templates.PollingConnectorTemplate.csproj index 4c4720298f..65119de126 100644 --- a/dotnet/templates/EventDrivenTelemetryConnector/EventDrivenTelemetryConnector.csproj +++ b/dotnet/templates/content/PollingConnectorTemplate/Azure.Iot.Operations.Templates.PollingConnectorTemplate.csproj @@ -1,4 +1,4 @@ - + net9.0 @@ -9,7 +9,6 @@ - + - diff --git a/dotnet/templates/PollingTelemetryConnector/DatasetSampler.cs b/dotnet/templates/content/PollingConnectorTemplate/DatasetSampler.cs similarity index 100% rename from dotnet/templates/PollingTelemetryConnector/DatasetSampler.cs rename to dotnet/templates/content/PollingConnectorTemplate/DatasetSampler.cs diff --git a/dotnet/templates/PollingTelemetryConnector/DatasetSamplerProvider.cs b/dotnet/templates/content/PollingConnectorTemplate/DatasetSamplerProvider.cs similarity index 62% rename from dotnet/templates/PollingTelemetryConnector/DatasetSamplerProvider.cs rename to dotnet/templates/content/PollingConnectorTemplate/DatasetSamplerProvider.cs index 5b957b15d4..46c7e55d8b 100644 --- a/dotnet/templates/PollingTelemetryConnector/DatasetSamplerProvider.cs +++ b/dotnet/templates/content/PollingConnectorTemplate/DatasetSamplerProvider.cs @@ -7,6 +7,9 @@ namespace PollingTelemetryConnectorTemplate { + /// + /// The factory for creating the samplers for each dataset. + /// public class DatasetSamplerProvider : IDatasetSamplerFactory { public static Func Factory = service => @@ -16,8 +19,9 @@ public class DatasetSamplerProvider : IDatasetSamplerFactory public IDatasetSampler CreateDatasetSampler(string deviceName, Device device, string inboundEndpointName, string assetName, Asset asset, AssetDataset dataset, EndpointCredentials? endpointCredentials) { - // this method should return the appropriate dataset sampler implementation for the provided asset + dataset. This - // method may be called multiple times if the asset or dataset changes in any way over time. + // As the connector discovers each dataset, it will need to know how to sample that dataset. To figure that + // out, this callback is invoked to provide context on which dataset was discovered and what device + endpoint + asset it + // belongs to. This callback may be called multiple times if the asset or dataset changes in any way over time. throw new NotImplementedException(); } } diff --git a/dotnet/templates/content/PollingConnectorTemplate/LeaderElectionConfigurationProvider.cs b/dotnet/templates/content/PollingConnectorTemplate/LeaderElectionConfigurationProvider.cs new file mode 100644 index 0000000000..2fb3b5addf --- /dev/null +++ b/dotnet/templates/content/PollingConnectorTemplate/LeaderElectionConfigurationProvider.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Azure.Iot.Operations.Connector; + +namespace PollingTelemetryConnectorTemplate +{ + /// + /// Factory that provides all leader election configurations for this connector. + /// + /// + /// Connectors can have active/passive replication by deploying more than one replica and having each replica + /// provide the same leadership position Id. That way, only one replica is the leader at a time. + /// + /// If no replication of this connector is needed, then this class can be deleted. + /// + public class LeaderElectionConfigurationProvider : IConnectorLeaderElectionConfigurationProvider + { + public static Func Factory = service => + { + return new LeaderElectionConfigurationProvider(); + }; + + public ConnectorLeaderElectionConfiguration GetLeaderElectionConfiguration() + { + // This value should be the same across any replicas but should be unique from connector to connector. + string leadershipPositionId = "some-leadership-position-id"; + return new(leadershipPositionId, TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(9)); + } + } +} diff --git a/dotnet/templates/PollingTelemetryConnector/MessageSchemaProvider.cs b/dotnet/templates/content/PollingConnectorTemplate/MessageSchemaProvider.cs similarity index 68% rename from dotnet/templates/PollingTelemetryConnector/MessageSchemaProvider.cs rename to dotnet/templates/content/PollingConnectorTemplate/MessageSchemaProvider.cs index 5b05c252bf..f5bbfb8f74 100644 --- a/dotnet/templates/PollingTelemetryConnector/MessageSchemaProvider.cs +++ b/dotnet/templates/content/PollingConnectorTemplate/MessageSchemaProvider.cs @@ -6,6 +6,15 @@ namespace PollingTelemetryConnectorTemplate { + /// + /// The factory method for determining what message schema should be registered for and attached to each + /// emitted telemetry message for each dataset handled by this connector. If no message schema is needed, + /// then this class can be left as-is. + /// + /// + /// Registering message schemas allows the receiver of a message to fetch this schema from the schema + /// registry service. With that schema, the receiver can correctly deserialize each received message's payload. + /// internal class MessageSchemaProvider : IMessageSchemaProvider { public static Func Factory = service => diff --git a/dotnet/templates/PollingTelemetryConnector/Program.cs b/dotnet/templates/content/PollingConnectorTemplate/Program.cs similarity index 76% rename from dotnet/templates/PollingTelemetryConnector/Program.cs rename to dotnet/templates/content/PollingConnectorTemplate/Program.cs index 3cc6ad22f5..5babcb83d2 100644 --- a/dotnet/templates/PollingTelemetryConnector/Program.cs +++ b/dotnet/templates/content/PollingConnectorTemplate/Program.cs @@ -2,12 +2,9 @@ // Licensed under the MIT License. using Azure.Iot.Operations.Connector; -using Azure.Iot.Operations.Connector.ConnectorConfigurations; using Azure.Iot.Operations.Protocol; using PollingTelemetryConnectorTemplate; -string connectorClientId = Environment.GetEnvironmentVariable(ConnectorFileMountSettings.ConnectorClientIdEnvVar) ?? throw new InvalidOperationException("No MQTT client Id configured by Akri operator"); - IHost host = Host.CreateDefaultBuilder(args) .ConfigureServices(services => { diff --git a/dotnet/templates/content/PollingConnectorTemplate/Worker.cs b/dotnet/templates/content/PollingConnectorTemplate/Worker.cs new file mode 100644 index 0000000000..80e2283560 --- /dev/null +++ b/dotnet/templates/content/PollingConnectorTemplate/Worker.cs @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Azure.Iot.Operations.Templates.PollingConnectorTemplate +{ + public class Worker : BackgroundService + { + private readonly ILogger _logger; + + public Worker(ILogger logger) + { + _logger = logger; + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + while (!stoppingToken.IsCancellationRequested) + { + if (_logger.IsEnabled(LogLevel.Information)) + { + _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now); + } + await Task.Delay(1000, stoppingToken); + } + } + } +} diff --git a/dotnet/templates/PollingTelemetryConnector/appsettings.Development.json b/dotnet/templates/content/PollingConnectorTemplate/appsettings.Development.json similarity index 100% rename from dotnet/templates/PollingTelemetryConnector/appsettings.Development.json rename to dotnet/templates/content/PollingConnectorTemplate/appsettings.Development.json diff --git a/dotnet/templates/PollingTelemetryConnector/appsettings.json b/dotnet/templates/content/PollingConnectorTemplate/appsettings.json similarity index 100% rename from dotnet/templates/PollingTelemetryConnector/appsettings.json rename to dotnet/templates/content/PollingConnectorTemplate/appsettings.json