| title | description | services | keywords | author | manager | ms.author | ms.date | ms.topic | ms.service |
|---|---|---|---|---|---|---|---|---|---|
Use Visual Studio Code to develop a C# module with Azure IoT Edge | Microsoft Docs |
Develop and deploy a C# module with Azure IoT Edge in Visual Studio Code, without context switching. |
iot-edge |
shizn |
timlt |
xshi |
01/11/2018 |
article |
iot-edge |
This article provides detailed instructions for using Visual Studio Code as the main development tool to develop and deploy your Azure IoT Edge modules.
This tutorial assumes that you are using a computer or virtual machine running Windows or Linux as your development machine. Your IoT Edge device can be another physical device, or you can simulate your IoT Edge device on your development machine.
Before you start this guidance, complete the following tutorials:
- Deploy Azure IoT Edge on a simulated device in Windows or Linux
- Develop and deploy a C# IoT Edge module to your simulated device
Here is a checklist that shows the items you should have after you finish the preceding tutorials:
- Visual Studio Code
- Azure IoT Edge extension for Visual Studio Code
- C# for Visual Studio Code (powered by OmniSharp) extension
- Docker
- .NET Core 2.0 SDK
- Python 2.7
- IoT Edge control script
- AzureIoTEdgeModule template (
dotnet new -i Microsoft.Azure.IoT.Edge.Module) - An active IoT hub with at least an IoT Edge device
It is also helpful to install Docker support for VS Code to better manage your module images and containers.
There are two ways to list your IoT hub devices in VS Code. You can choose either way to continue.
-
In the command palette (F1 or Ctrl + Shift + P), type and select Azure: Sign in. Then select Copy & Open. Paste (Ctrl + V) the code in your browser, and select Continue. Then sign in with your Azure account. You can see your account info in the VS Code status bar.
-
In the command palette, type and select IoT: Select IoT Hub. First, select the subscription where you created your IoT hub in the previous tutorial. Then, choose the IoT hub that contains the IoT Edge device.
In the command palette, type and select IoT: Set IoT Hub Connection String. Make sure you paste the connecting string under policy iothubowner. (You can find it in the shared access policies of your IoT hub in the Azure portal.)
You can see the device list in IoT Hub Devices Explorer, in the side bar on the left.
Install and start the Azure IoT Edge runtime on your device. Deploy a simulated sensor module that sends telemetry data to Azure IoT Hub.
-
In Command Palette, select Edge: Setup Edge and choose your IoT Edge device ID. Alternatively, right-click the IoT Edge device ID in Device List, and select Setup Edge.
-
In the command palette, select Edge: Start Edge to start your IoT Edge runtime. You can see corresponding outputs in the integrated terminal.
-
Check the IoT Edge runtime status in the Docker Explorer. Green means it's running, and your IoT Edge runtime started successfully. Your computer now simulates an IoT Edge device.
-
Simulate a sensor that keeps sending messages to your IoT Edge device. In the command palette, type and select Edge: Generate Edge configuration file. Select a folder to create this file. In the deployment.json file that is generated, replace the content
<registry>/<image>:<tag>withmicrosoft/azureiotedge-simulated-temperature-sensor:1.0-preview, and save the file. -
Select Edge: Create deployment for Edge device, and choose the IoT Edge device ID to create a new deployment. Alternatively, you can right-click the IoT Edge device ID in the device list, and select Create deployment for Edge device.
-
You should see your IoT Edge start running in the Docker Explorer with the simulated sensor. Right-click the container in Docker Explorer. You can watch Docker logs for each module. Also, you can view the module list in the device list.
-
Right-click your IoT Edge device ID, and you can monitor D2C messages in VS Code.
-
To stop your IoT Edge runtime and the sensor module, type and select Edge: Stop Edge in the command palette.
In the tutorial Develop a C# module, you update, build, and publish your module image in VS Code. Then you go to the Azure portal to deploy your C# module. This section introduces how to use VS Code to deploy and monitor your C# module.
You can use any Docker-compatible registry for this tutorial. Two popular Docker registry services available in the cloud are Azure Container Registry and Docker Hub. This section uses a local Docker registry, which is easier for testing during your early development. In the VS Code integrated terminal (Ctrl + `), run the following command to start a local registry:
docker run -d -p 5000:5000 --name registry registry:2
Note
This example shows registry configurations that are only appropriate for testing. A production-ready registry must be protected by TLS, and should ideally use an access-control mechanism. We recommend you use Azure Container Registry or Docker Hub to deploy production-ready IoT Edge modules.
The following steps show you how to create an IoT Edge module based on .NET Core 2.0, by using Visual Studio Code and the Azure IoT Edge extension. If you have completed this section in the previous tutorial, you can safely skip this section.
-
In Visual Studio Code, select View > Integrated Terminal to open the VS Code integrated terminal.
-
In the integrated terminal, enter the following command to install (or update) the AzureIoTEdgeModule template in dotnet:
dotnet new -i Microsoft.Azure.IoT.Edge.Module -
Create a project for the new module. The following command creates the project folder, FilterModule, in the current working folder:
dotnet new aziotedgemodule -n FilterModule -
Select File > Open Folder.
-
Browse to the FilterModule folder, and click Select Folder to open the project in VS Code.
-
In VS Code Explorer, select Program.cs to open it. At the top of program.cs, include the following namespaces:
using Microsoft.Azure.Devices.Shared; using System.Collections.Generic; using Newtonsoft.Json;
-
Add the
temperatureThresholdvariable to the Program class. This variable sets the value that the measured temperature must exceed in order for the data to be sent to IoT Hub.static int temperatureThreshold { get; set; } = 25;
-
Add the
MessageBody,Machine, andAmbientclasses to the Program class. These classes define the expected schema for the body of incoming messages.class MessageBody { public Machine machine {get;set;} public Ambient ambient {get; set;} public string timeCreated {get; set;} } class Machine { public double temperature {get; set;} public double pressure {get; set;} } class Ambient { public double temperature {get; set;} public int humidity {get; set;} }
-
In the Init method, the code creates and configures a DeviceClient object. This object allows the module to connect to the local IoT Edge runtime to send and receive messages. The IoT Edge runtime supplies to the module the connection string used in the Init method. After creating the DeviceClient object, the code registers a callback for receiving messages from the IoT Edge hub via the input1 endpoint. Replace the
SetInputMessageHandlerAsyncmethod with a new one, and add aSetDesiredPropertyUpdateCallbackAsyncmethod for desired properties updates. To make this change, replace the last line of the Init method with the following code:// Register callback to be called when a message is received by the module // await ioTHubModuleClient.SetImputMessageHandlerAsync("input1", PipeMessage, iotHubModuleClient); // Attach callback for Twin desired properties updates await ioTHubModuleClient.SetDesiredPropertyUpdateCallbackAsync(onDesiredPropertiesUpdate, null); // Register callback to be called when a message is received by the module await ioTHubModuleClient.SetInputMessageHandlerAsync("input1", FilterMessages, ioTHubModuleClient);
-
Add the
onDesiredPropertiesUpdatemethod to the Program class. This method receives updates on the desired properties from the module twin, and updates the temperatureThreshold variable to match. All modules have their own module twin, which lets you configure the code running inside a module directly from the cloud.static Task onDesiredPropertiesUpdate(TwinCollection desiredProperties, object userContext) { try { Console.WriteLine("Desired property change:"); Console.WriteLine(JsonConvert.SerializeObject(desiredProperties)); if (desiredProperties["TemperatureThreshold"]!=null) temperatureThreshold = desiredProperties["TemperatureThreshold"]; } catch (AggregateException ex) { foreach (Exception exception in ex.InnerExceptions) { Console.WriteLine(); Console.WriteLine("Error when receiving desired property: {0}", exception); } } catch (Exception ex) { Console.WriteLine(); Console.WriteLine("Error when receiving desired property: {0}", ex.Message); } return Task.CompletedTask; }
-
Replace the
PipeMessagemethod with theFilterMessagesmethod. This method is called whenever the module receives a message from IoT Edge Hub. It filters out messages that report temperatures below the temperature threshold set via the module twin. It also adds the MessageType property to the message with the value set to Alert.static async Task<MessageResponse> FilterMessages(Message message, object userContext) { int counterValue = Interlocked.Increment(ref counter); try { DeviceClient deviceClient = (DeviceClient)userContext; byte[] messageBytes = message.GetBytes(); string messageString = Encoding.UTF8.GetString(messageBytes); Console.WriteLine($"Received message {counterValue}: [{messageString}]"); // Get message body var messageBody = JsonConvert.DeserializeObject<MessageBody>(messageString); if (messageBody != null && messageBody.machine.temperature > temperatureThreshold) { Console.WriteLine($"Machine temperature {messageBody.machine.temperature} " + $"exceeds threshold {temperatureThreshold}"); var filteredMessage = new Message(messageBytes); foreach (KeyValuePair<string, string> prop in message.Properties) { filteredMessage.Properties.Add(prop.Key, prop.Value); } filteredMessage.Properties.Add("MessageType", "Alert"); await deviceClient.SendEventAsync("output1", filteredMessage); } // Indicate that the message treatment is completed return MessageResponse.Completed; } catch (AggregateException ex) { foreach (Exception exception in ex.InnerExceptions) { Console.WriteLine(); Console.WriteLine("Error in sample: {0}", exception); } // Indicate that the message treatment is not completed DeviceClient deviceClient = (DeviceClient)userContext; return MessageResponse.Abandoned; } catch (Exception ex) { Console.WriteLine(); Console.WriteLine("Error in sample: {0}", ex.Message); // Indicate that the message treatment is not completed DeviceClient deviceClient = (DeviceClient)userContext; return MessageResponse.Abandoned; } }
-
To build the project, right-click the FilterModule.csproj file in Explorer, and select Build IoT Edge module. This process compiles the module, and exports the binary and its dependencies into a folder that is used to create a Docker image.
-
In VS Code Explorer, expand the Docker folder. Then expand the folder for your container platform, either linux-x64 or windows-nano.
-
Right-click the Dockerfile file, and select Build IoT Edge module Docker image.
-
In the Select Folder window, either browse to or enter
./bin/Debug/netcoreapp2.0/publish. Select Select Folder as EXE_DIR. -
In the pop-up text box at the top of the VS Code window, enter the image name. For example:
<your container registry address>/filtermodule:latest. If you are deploying to local registry, it should belocalhost:5000/filtermodule:latest. -
Push the image to your Docker repository. Use the Edge: Push IoT Edge module Docker image command, and enter the image URL in the pop-up text box at the top of the VS Code window. Use the same image URL you used in the preceding step. Check the console log to make sure the image has been successfully pushed.
-
Open the
deployment.jsonfile, and replace the modules section with the following:"tempSensor": { "version": "1.0", "type": "docker", "status": "running", "restartPolicy": "always", "settings": { "image": "microsoft/azureiotedge-simulated-temperature-sensor:1.0-preview", "createOptions": "" } }, "filtermodule": { "version": "1.0", "type": "docker", "status": "running", "restartPolicy": "always", "settings": { "image": "localhost:5000/filtermodule:latest", "createOptions": "" } }
-
Replace the routes section with the following:
"sensorToFilter": "FROM /messages/modules/tempSensor/outputs/temperatureOutput INTO BrokeredEndpoint(\"/modules/filtermodule/inputs/input1\")", "filterToIoTHub": "FROM /messages/modules/filtermodule/outputs/output1 INTO $upstream"
[!NOTE] Declarative rules in the runtime define where those messages flow. In this tutorial, you need two routes. The first route transports messages from the temperature sensor to the filter module via the "input1" endpoint. This is the endpoint that you configured with the FilterMessages handler. The second route transports messages from the filter module to IoT Hub. In this route, upstream is a special destination that tells IoT Edge Hub to send messages to IoT Hub.
-
Save this file.
-
In the command palette, select Edge: Create deployment for Edge device. Then select your IoT Edge device ID to create a deployment. Or, right-click the device ID in the device list, and select Create deployment for Edge device.
-
Select the
deployment.jsonyou updated. In the output window, you can see corresponding outputs for your deployment. -
Start your IoT Edge runtime in the command palette (select Edge: Start Edge).
-
You can see your IoT Edge runtime start running in the Docker Explorer, with the simulated sensor and filter module.
-
Right-click your IoT Edge device ID, and you can monitor D2C messages in VS Code.
In this tutorial, you created an IoT Edge module, and deployed it to an IoT Edge device in VS Code. To learn about other scenarios when you are developing Azure IoT Edge in VS Code, see the following tutorial:
[!div class="nextstepaction"] Debug C# module in VS Code












