Struct Equality and SkipLocalsInit

I have recently learned an interesting behavior of the .NET runtime on equality from a post on Mastodon. The post points out that RuntimeHelpers.Equals returns whether the input arguments' underlying memory are equal, which may not be true always, even when the values are equal.

Under the hood RuntimeHelpers.Equals uses memcmp to compare the memory representation of two objects.

Padding

In C# structs may have paddings in the memory representation. For example, the following struct will have a padding on x64, so that the value is aligned to 8 bytes:

Find out more


Cross Compile on Windows 11 to Linux ARM64 (Raspberry)

The quickest and easiest way to cross compile NativeAot on Windows to a Raspberry Pi is using PublishAotCross nuget package.

Set <PublishAot> to true and install nuget package PublishAotCross.

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <PublishAot>true</PublishAot>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="PublishAotCross" Version="1.0.0" />
  </ItemGroup>
  
</Project>

Package requires zig, download and extract it to any folder.

Find out more


Running ASP.NET Core 9 on a Raspberry Pi Zero 2W

This is a step by step for setting up a Raspberry Pi Zero 2W with a default ASP.NET Core 9 application (in 9 steps).

  1. Install the Raspberry Pi Imager tool.

  2. Install Raspberry Pi OS Lite (64bit) on the SD Card. Configure settings Wi-Fi/user/SSH settings during the installation.

  3. SSH into the raspberry using ssh <user>@raspberrypi.local or ssh <ip> -l <user> command.

  4. Install .NET runtime:

  • Follow documentation outlined by dotnet iot. Here I am using the Framework-Dependent approach.

  • curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --channel STS

  • Set PATH: echo 'export DOTNET_ROOT=$HOME/.dotnet' >> ~/.bashrc then echo 'export PATH=$PATH:$HOME/.dotnet' >> ~/.bashrc and source ~/.bashrc

  • Run dotnet --version to validate that installation succeeded.

  1. Create a folder mkdir app on the Raspberry Pi for the application.

  2. Publish the web application in Release, Portable, .NET 9, Framework-Dependent mode on any dev machine.

  3. Copy the published application to the Raspberry Pi using scp: scp -r D:\repos\..\WebApplication\bin\Release\net9.0\publish\* <user>@raspberrypi:/home/<user>/app executed on the dev machine.

  4. To run locally the service on port 80 (443 would require a certificate), execute the following command: sudo /home/<user>/.dotnet/dotnet /home/<user>/app/WebApplication.dll --urls http://+:80, where sudo is required for port 80 (using port 5000 can bind without elevated privileges).

  5. Setup the application to start after boot using systemd ref:

Find out more


Constructing URLs

HttpClient type in .NET is one of the most dominant types to create network calls using HTTP protocol. One of the questions I face every time: how can I build the Uri that is then passed to HttpRequestMessage or HttpClient to identify the resource to be requested. The API surface of these types accepts strings and Uris, and Uris can be built from strings.

Many line of business (LOB) applications also need to present links/URI that point out from the current application to some external resource. The parts of these URIs typically get concatenated from a well-known host, port, some path that may vary based on the resource and a query string.

In this post I am going explore different ways of creating URIs, focusing on creating the path segments. While schemas, hosts, ports, or query strings are going to be part of the final URI built, I am going to handle them as well formed constants for the purpose of this blog post. I do this because most applications define the base URIs in the settings, including the schema, the host and the port, such as https://localhost:5000/. The path typically varies on the resource to be referenced. The query can also vary, but many RESTful APIs tend to choose path parameters and request bodies instead. However, the findings and concepts described in this post for the paths can generally applied for the other parts of the URI as well.

I am writing this blog post in the .NET 8 timeframe. This post uses the API surface of the preview versions of .NET 9.

Find out more


Kestrel HTTP/2 Internals

In the previous post I explored some of the inner workings of Kestrel. Kestrel is one of the servers built into ASP.NET Core.

First, I investigated how HTTP socket connections are dispatched to a request processor, such as the Http2Connection.

In a different post I looked into how HEADER frames work with HTTP/2 responses, and what are the main building blocks of writing headers to the response stream in Kestrel.

Lastly, I explored how HEADER and CONTINUATION frames are used in ASP.NET Core to serve response headers larger to the frame size.

Find out more