Click here to Skip to main content
15,887,485 members
Articles / Internet of Things
Article

Running ASP.NET Core Web Server on Arm64

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
8 Sep 2023CPOL8 min read 3.2K   10   1  
This article demonstrates how you can use ASP.NET Core with Windows 11 to build a web server for a headless IoT application. You will gain insights into harnessing Arm64-powered devices that offer high performance while consuming minimal power for your IoT applications.

This article is a sponsored article. Articles such as these are intended to provide you with information on products and services that we consider useful and of value to developers

Image 1

ASP.NET Core is a cross-platform framework for building web applications that lets you develop web services as back ends for various scenarios. It also supports containerization, which you can use for building cloud-native apps. These characteristics and its cross-platform design make ASP.NET Core an ideal tool for building Internet of Things (IoT) web servers.

Arm64 (sometimes written as AArch64 or ARM64) chip architecture allows you to create high-performance, power-efficient applications. Windows 11 can run directly on Arm64-powered devices, so you can use it similarly to Windows 10 IoT Core to develop IoT apps. For example, you can use ASP.NET Core to build a web API that your headless IoT device exposes to communicate with users or other devices.

By building ASP.NET apps to target Arm64 natively, you can achieve performance superior to an emulation approach while enjoying low power consumption. As we demonstrated in the first part of this series, building an app to use Arm64 natively can reduce the computation time almost threefold compared to emulation.

Also, Microsoft has introduced Windows Dev Kit 2023, which provides a convenient, compact, development-friendly device powered by an Arm64 Snapdragon chip. The device contains a neural processing unit and a GPU, enabling you to create high-performance, intelligent applications.

This article demonstrates how you can use ASP.NET Core with Windows 11 to build a web server for a headless IoT application. You will gain insights into harnessing Arm64-powered devices that offer high performance while consuming minimal power for your IoT applications.

This article uses Windows Dev Kit 2023 as a development PC. The kit does not contain any real sensors, so you will implement a temperature sensor emulator.

You can find the companion code here.

Project Setup

Start by installing the .NET 8.0 SDK. You must install an SDK for Windows running on Arm64 architecture. The installation is straightforward and does not require instructions. As explained in the previous article, the .NET 8.0 SDK provides you with the .NET command line interface (dotnet command), which you use to create and run the project. Note that when you install the SDK for Arm64 on a supported Arm64-powered device, the dotnet command automatically defaults to using Arm64 architecture for your project.

Next, install Visual Studio Code for Windows by selecting User Installer for Arm64. Then, launch the installer and use the default settings. After installation, pick your color theme. Alternatively, you can install Visual Studio 2022 with ASP.NET and the web development workload.

Now, you will create a new ASP.NET Core Web API project.

Open a command prompt window and type the following command:

Terminal
dotnet new webapi -o Arm64.HeadlessIoT

This command generates the output shown below:

Image 2

The command creates a project containing a web API controller implemented in the Controllers/WeatherForecastController.cs file. This controller returns a collection of simulated weather forecasts. Since you do not need this controller, remove it by deleting the entire WeatherForecastController.cs file. The project is now ready, and you can proceed with implementation.

Implementation

This section demonstrates how to implement the temperature sensor emulator, sensor service registration, and web API controller. Next, it outlines how to test the web API server.

Temperature Sensor Emulator

You start by implementing the temperature sensor emulator, which simulates readings from a temperature sensor connected to an IoT device running a web service.

To represent sensor readings, you use the SensorReading class, defined in the code snippet below. To implement this class, create a Sensors folder in the Arm64.HeadlessIoT solution folder, then make a new file called SensorReading.cs, where you place the following code:

C#
namespace Arm64.HeadlessIoT.Sensors;
 
public class SensorReading 
{
    public double Value { get; private set; }
 
    public DateTime TimeStamp { get; }
 
    public SensorReading(double value)
    {
        Value = value;
        TimeStamp = DateTime.UtcNow;
    }
}

The class above contains two properties: Value and TimeStamp. The Value property stores the sensor reading, while TimeStamp represents the time the reading was obtained. The SensorReading class also implements the constructor. You use this class to populate the Value property with the constructor parameter. The TimeStamp automatically provides the current date and time in UTC format.

Then, in the Sensors folder, create another file, ISensor.cs, which defines the following interface:

C#
namespace Arm64.HeadlessIoT.Sensors;
 
public interface ISensor 
{
    public bool IsActive { get; set; }
 
    public SensorReading GetCurrentReading(); 
}

This interface provides a common contract for classes implementing sensor emulators. In this case, all the classes implementing the interface must implement the following two members:

  • IsActive — a Boolean property specifying whether the sensor is active and currently recording data
  • GetCurrentReading — a method returning an instance of the SensorReading class containing a sensor reading and timestamp

Now, you can implement the actual class representing the temperature sensor. In the Sensors folder, add another file, TemperatureSensor.cs, which defines the following class:

C#
namespace Arm64.HeadlessIoT.Sensors;
 
public class TemperatureSensor : ISensor
{
    private const int minValue = -10;
 
    private const int maxValue = 40;
 
    private SensorReading lastKnownReading 
        = new SensorReading(random.Next(minValue, maxValue));
 
    private static Random random = new();
 
    public bool IsActive {get; set;} = true;
    
    public SensorReading GetCurrentReading() 
    {
        if(IsActive)
        {
            var currentSensorReading = new SensorReading(random.Next(minValue, maxValue));
 
            lastKnownReading = currentSensorReading;
 
            return currentSensorReading;
        }
        else
        {
            return lastKnownReading;
        }
    }    
}

The TemperatureSensor class implements the ISensor interface, the IsActive property, and the GetCurrentReading method. The IsActive property is a Boolean value, which is initially true, indicating that the temperature sensor emulator is active.

The second method, GetCurrentReading, checks if the IsActive property is true. If so, the GetCurrentReading method simulates a temperature reading using a pseudo-random number generator (the System.Random class instance). Specifically, it uses the Next method of this generator to pick an integer value from a range of values stored in the min and max fields of the TemperatureSensor class. The lastKnownReading field stores the sensor reading. Finally, the GetCurrentReading method will return the temperature reading to the caller.

Alternatively, if the IsActive property is false, the GetCurrentReading method will return the last known sensor reading.

Sensor Service Registration

After implementing the temperature emulator, you use the dependency injection design pattern to register an instance of the TemperatureSensor as a singleton. To do this, you must modify the Program.cs file by adding using Arm64.HeadlessIoT.Sensors and builder.Services.AddSingleton<ISensor, TemperatureSensor>() as they appear below:

C#
using Arm64.HeadlessIoT.Sensors;
 
var builder = WebApplication.CreateBuilder(args);
 
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
 
builder.Services.AddSingleton<ISensor, TemperatureSensor>();
 
var app = builder.Build();
 
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}
 
app.UseHttpsRedirection();
 
app.UseAuthorization();
 
app.MapControllers();
 
app.Run();

This approach ensures that a single instance of the TemperatureSensor class is available to the entire application. Any web API controller requiring access to that sensor can simply use constructor injection.

You will also use the Swagger toolset. As shown above, the default ASP.NET Core Web API project template also registers two services: EndpointsApiExplorer and SwaggerGen.

C#
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

You use these services to add Swagger middleware, which analyzes all the controllers in the project. It then generates a JSON-formatted file containing documentation of your web APIs and exposes the generated documentation on the HTTP endpoint using the following statements:

C#
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

Web API Controller for the Headless IoT Device

Now you are ready to implement the web API controller. Create a new file, IoTController.cs, in the Controllers folder. Then, in the IoTController.cs file, add two using statements and define the namespace:

C#
using Microsoft.AspNetCore.Mvc;
using Arm64.HeadlessIoT.Sensors;
 
namespace Arm64.HeadlessIoT.Controllers;

Next, define the IoTController class, which derives from the ControllerBase and contains the required controller attributes:

C#
[ApiController]
[Route("[controller]")]
public class IoTController : ControllerBase
{
    
}

Then, in the IoTController class, define the read-only field, temperatureSensor, which stores the reference to the TemperatureSensor class instance registered in the dependency container in the Program.cs file:

C#
private readonly ISensor temperatureSensor;

You can now define the IoTController class constructor:

C#
public IoTController(ISensor sensor)
{
    temperatureSensor = sensor;
}

This code uses constructor dependency injection to obtain a reference to the TemperatureSensor class instance. The temperatureSensor field stores the reference to the TemperatureSensor class as defined in the Program.cs file.

Now, you can implement the IoTController method, which handles GET requests:

C#
[HttpGet]
[ProducesResponseType(typeof(SensorReading), StatusCodes.Status200OK)]
public SensorReading Get()
{
    return temperatureSensor.GetCurrentReading();
}

This method returns the temperature sensor emulator’s current reading.

Finally, you implement the POST handler, which enables a user to change the sensor emulator’s IsActive property:

C#
[HttpPost]
public IActionResult SetSensorStatus(bool isActive)
{
    temperatureSensor.IsActive = isActive;
 
    return Ok();
}

Now, you can change the internal state of the emulator through the web API.

Testing the Web API Server

To test the web API server, you must build and run the app.

Open the command prompt window, go to the project’s folder and type:

Terminal
dotnet run

This command produces the following output:

Image 3

Note that the command uses Arm64 architecture as a default (because you installed .NET SDK for Arm64). If you have multiple SDKs available, you must explicitly specify the architecture using the -a parameter. For example:

Terminal
dotnet run -a arm64

You can ensure the app uses this architecture by opening the Task Manager and clicking the Details pane:

Image 4

Now, open the web browser and navigate to http://localhost:<port>/iot, where <port> should match the port value shown after Now listening on in the command prompt screenshot above. Doing this invokes the GET method of IoTController, and you see the sensor reading rendered as a JSON-formatted string:

Image 5

To test the POST method, use curl, Postman, or Swagger. The last option is the simplest, as Swagger is available in the project template.

To access Swagger, type http://localhost:<port>/swagger in the web browser’s address bar. This URL takes you to the following screen:

Image 6

Now, expand the POST section and click the Try it out button, which enables the isActive drop-down list. Set isActive to false, and then click Execute.

Image 7

This action sends the POST request to IoTController and disables the emulator. So, all subsequent GET calls to IoTController return the last known sensor reading (which is the final reading generated before disabling the emulator), as shown below:

Image 8

When you set isActive back to true and send the GET request to the web server, you will see the temperature setting update.

Summary

This article demonstrated using ASP.NET Core to implement a web API server for headless IoT apps running on Windows 11 on Arm. It visualized how the web server can retrieve simulated sensor readings from a temperature sensor emulator. It also showed how to control the emulator through a web server. Finally, it demonstrated using dependency injection in ASP.NET Core and Swagger to test a web API. ASP.NET Core is cross-platform, allowing you to use a similar approach to run web servers on non-Windows platforms.

By combining ASP.NET Core with Arm64, you can implement high-performance, low-power consumption web servers for all your applications. Although you can compile the project for any CPU, when you target Arm64, you improve the web server’s performance by running natively.

Try Arm64 yourself to learn more.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
Dawid Borycki is a software engineer and biomedical researcher with extensive experience in Microsoft technologies. He has completed a broad range of challenging projects involving the development of software for device prototypes (mostly medical equipment), embedded device interfacing, and desktop and mobile programming. Borycki is an author of two Microsoft Press books: “Programming for Mixed Reality (2018)” and “Programming for the Internet of Things (2017).”

Comments and Discussions

 
-- There are no messages in this forum --