Skip to main content

Posts

Showing posts from December, 2022

Impress your colleagues with your knowledge about..the PrintMembers method

Sometimes when working with C# you discover some hidden gems. Some of them very useful, other ones a little bit harder to find a good way to benefit from their functionality. One of those hidden gems that I discovered some days ago is the PrintMembers method. Record Types To explain where you can find this method, I first have to talk about record types .  Record types were introduced in C# 9 as a new reference type that you can create instead of classes or structs. C# 10 adds record structs so that you can define records as value types. Records are distinct from classes in that record types use value-based equality . Two variables of a record type are equal if the record type definitions are identical, and if for every field, the values in both records are equal. Record types have a compiler-generated ToString method that displays the names and values of public properties and fields: Person{ FirstName = Bart, LastName = Wullems } In an application we are building we ar

Use the power of Source Generators with Lombok.NET

Since the introduction of source generators in .NET 5 , I always wondered what the cool use cases would be that this feature makes possible. Today I want to introduce to you Lombok.NET , as an example of what Source Generators make possible. Lombok.NET If you are a Java developer, the name ‘Lombok’ maybe rings a bell. Lombok.NET is inspired by Project Lombok , a Java library with as main goal to help you minimize the amount of boilerplate code you need to write. I have no clue how this exactly works in Java, but Lombok.NET has the same goal using Source Generators. Here are the list of features that Lombok.NET supports today: Constructors "With" methods Singletons Lazy INotifyPropertyChanged/INotifyPropertyChanging Async overloads ToString Decorator pattern Let’s have a look at 2 of them that I use the most. Installation Before we can use Lombok.NET, we need to install it first. this is quite easy because it is just a NuGet packag

Azure Pipelines–Skip if global tool is already installed

In my yesterday post , I installed and used a dotnet global tool to generate an SBOM. If you were really paying attention, you maybe noticed that I did something special to install the tool. This is the topic of today's post. In my original attempt to install the SBOM .NET tool, I used the following task: And this is the task I used in the end: Do you notice the difference? The difference is in the Arguments section. I originally used the install argument and switched later to an update argument. Let me explain why… When I executed the original pipeline for a second time, it no longer worked and I got the following error: Starting: dotnet install SBOM tool ============================================================================== Task : .NET Core Description : Build, test, package, or publish a dotnet application, or run a custom dotnet command Version : 2.174.0 Author : Microsoft Corporation Help : https://docs.microsoft.com/azure/devops/pipeline

Azure Pipelines - Generate your software bill of materials (SBOM) **Updated**

A few months ago, I introduced the concept of an SBOM(Software Bill of Materials) and how you could integrate this in your Azure DevOps Pipelines. A quick fix Last week I noticed that the builds where I was using this approach started to fail. Here is the error I got: "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command ". 'D:\b\2\_work\_temp\f7a4bfef-55b7-46ca-bc35-5fa4674dc781.ps1'" Encountered error while running ManifestTool generation workflow. Error: The value of PackageSupplier can't be null or empty. ##[error]PowerShell exited with code '1'. Finishing: Generate sbom Turns out that an updated version of the Microsoft sbom-tool was released. In this version a new required parameter was introduced; -ps <package supplier> So I opened the failing pipelines and added this extra argument: # Write your PowerShell commands here.

Azure Static Web App -Failed to create a Personal Access Token for this user in Azure DevOps

Last week I showed how you can build and deploy your web application to Azure Static Web Apps. As part of the configuration process, if you are using Azure DevOps or Github, a YAML pipeline or Github Actions pipeline can be created for you. Before you continue reading here, it is a good idea to (re)read the original post . Back? As I mentioned in the original ost, I couldn't get this working for the Azure DevOps instance I was using. I got the folowing error message: Failed to create a Personal Access Token for this user in Azure DevOps. Please deploy your app using the ‘Other’ deployment source instead of ‘Azure DevOps’. After the app is created, open it and follow the instructions to get the token and deploy your app. I followed the suggestion in the error message above and got everything up and running. But what if you want to fix this error? Let’s fix the error message The reason we got this error is because our Azure DevOps instance isn’t linked to Azure Act

HotChocolate–Disable Banana Cake Pop

Just by reading the title you would wonder what I’m talking about. HotChocolate is a GraphQL server implementation for .NET. And Banana Cake Pop is a GraphQL IDE (similar to Graphiql and GraphQL Playground) by the same authors. When you include the HotChocolate NuGet package( HotChocolate.AspNetCore ) in your ASP.NET Core application, Banana Cake Pop is installed and activated automatically. When you browse to the GraphQL endpoint (by default ‘/graphql’) using a browser Banana Cake Pop will be loaded: This is something that is really helpful during development but maybe not something you want in production. To disable Banana Cake Pop outside development you can configure this through the GraphQLServerOptions :

Running a Blazor WebAssembly App on Azure Static Web Apps

In my blog post yesterday I shared how I got into trouble when I tried to deploy a Blazor WebAssembly App to an Azure App Service for Linux. Turns out that this is not supported. However the documentation mentions that it should be possible using Azure Static Web Apps . So far I didn’t use Azure Static Web Apps, this is a good opportunity to finally give it a try… Create a Static Web App Go to the Azure portal . Select Create a Resource and search for Static Web Apps. Select Static Web App . Click on the Create Static Web App button or + Create if you already created a Static Web App before. On the Basics tab, choose a Subscription, Static Web App name and hosting plan. We also need to select a region for the Azure Functions API although we’ll not use it. And now comes the important part, we have to choose a deployment option. In my case I have the code available on Azure DevOps, so let’s choose that option and specify all the other deta

Running a Blazor WebAssembly app on Azure App Service for Linux

I hope this blog post becomes irrelevant in the future, we'll see. I was trying today to deploy a Blazor WebAssembly app on Linux. Although I was able to succesfully deploy the Blazor WebAssembly app through my Azure DevOps pipeline, the application didn't want to run???? After a lot of trial and error, I found the following information in the documentation : Blazor WebAssembly apps can be deployed to Azure App Services on Windows, which hosts the app on IIS . Deploying a standalone Blazor WebAssembly app to Azure App Service for Linux isn't currently supported. We recommend hosting a standalone Blazor WebAssembly app using Azure Static Web Apps , which supports this scenario. Whoopsy! I could have thought about this sooner, because when I tried to Publish the application through Visual Studio(right click on the Project –> Publish) only the Azure App Service(Windows) option was shown:

C# 11 – File Scoped Types

One of the new features in C# 11 is File Scoped Types also known as File Local Types. Although it sounds kindof familiar to File Scoped Namespaces introduced in C# 10, it is completely unrelated. As the name implies File Scoped types restrict the usage of a type to the current file. The file modifier To use this feature a new modifier was introduced; file . Applying this modifier to any type definition restrict its usage to the current file. In the screenshot above you can see that I created a File class in both the FileReader.cs file and FileWriter.cs file without any issues. If I try to use this File class outside these 2 files, I get an error: Good to know: The file modifier can be applied to class , interface, record, struct , enum , delegate . It cannot be combined with another modifier like internal or public . When should I use this feature? There are a few use cases I can think about where I see this feature useful: Code generation:

Kubernetes - Reload your ASP.NET Core configuration when a configmap changes–DOTNET_USE_POLLING_FILE_WATCHER

In a previous post I showed how you can use ConfigMaps in Kubernetes . This allows you to update for example our appsettings.json without the need to upload a new container image and update our pods. Sounds great! However there is one challenge with this approach. In Kubernetes a config map is mounted as a symlink, and .NET is not able to pick up changes applied to the original file by just knowing about the symlink. I mentioned some workarounds but an out-of-the-box solution was not available at that time. DOTNET_USE_POLLING_FILE_WATCHER Now a solution to the problem above is available through the DOTNET_USE_POLLING_FILE_WATCHER environment variable. By setting this value to “true” or “1”, we can instruct .NET to not use the default FileSystemWatcher but using a polling mechanism instead. More information: dotnet watch

YARP–Direct forwarding in .NET 6 and beyond

With YARP(Yet-Another-Reverse-Proxy) you can transform your ASP.NET Core application into a reverse proxy. It offers features like routing, discovery, load balancing, retries,... However in the application I'm building that is a lot more then what I need. I only need the ability to take a specific request and forward it to a specific destination. In that case you can use Direct Forwarding through the IHttpForwarder . IHttpForwarder supports: Dynamic destination selection, you specify the destination for each request Http client customization, you provide the HttpMessageInvoker Request and response customization (except bodies) Streaming protocols like gRPC and WebSockets Error handling It does not include: Routing Load balancing Affinity Retries Direct forwarding in .NET 6 and beyond You can find an example of Direct Forwarding in the documentation. However this documentation is written for .NET 5 still using the Startup.cs class

Testing a token protected API using user-jwts

Testing a token-protected API can be a challenge. You need to have an identity and access management solution in place to get a valid access token that can be passed to your API. .NET 7 makes this whole process easier by introducing a new command line tool; user-jwts . This allows you to generate JSON Web Tokens that can be used during development. Let me walk you through the steps to use this new tool. Getting started with user-jwts I have an existing ASP.NET Core application configured to use JTW Bearer authentication: I introduce a new endpoint that requires authorization: Before .NET 7 to be able to test this endpoint, we need to register this API in your IAM solution and log in by providing valid credentials. Not impossible to do, but still a lot of work... Let’s invoke the user-jwts tool: dotnet user-jwts create Executing this command will result in the following actions: A JWT token is created and stored as a ‘user secret’ on your local machine.

C# 11–Generic Attributes

C# 11 introduces a large list of new language features. One of the smaller features is the support for generic attributes. Before C# 11, when you had to pass type information to an attribute, you had to use a type parameter. Let’s use an example that always has annoyed me; the [ServiceFilterAttribute] . If you have ever used an ASP.NET MVC filter that needed dependencies, then you should know this attribute. Here is an example I copied from the Microsoft documentation : You see in the example above is that the type of the actual filter we want to invoke is passed as a parameter to the ServiceFilterAttribute. The constructor looks something like this: By not being able to use generics, I could pass anything I want as a parameter to the ServiceFilter no matter if it is actually a filter or not. The compiler will not help me to avoid passing an incorrect argument. A type safe ServiceFilter With the release of C# 11 and the introduction of Generic Attributes, we can creat

HotChocolate OpenTelemetry

HotChocolate remains my favorite GraphQL client for .NET. As I find it really important to monitor my applications, I have written multiple posts (here and here ) on how to integrate monitoring with HotChocolate. At the beginning of this year, with the release of HotChocolate 12.5 , support for OpenTelemetry was introduced. Although I updated my applications to start using it, it took me until now to write a corresponding blog post about it. Instrument your GraphQL Server with OpenTelemetry Let me walk you through the steps: We’ll start with an ASP.NET Core application with OpenTelemetry enabled. Therefore we added the following NuGet packages: OpenTelemetry.Extensions.Hosting OpenTelemetry.Instrumentation.AspNetCore OpenTelemetry.Instrumentation.Http OpenTelemetry.Instrumentation.SqlClient We also add a reference to the AzureMonitor exporter because we want to use Application Insights: Azure.Monitor.OpenTelemetry.Exporter O

Convert a project to use centralised package management

If you have never heard about Central Package Management(CPM), first have a look at my blog post a few months ago. Done reading? Ok, we continue... To summarize, with CPM you bring all your dependencies in one place (the Directory.Packages.props file). This makes it easier to manage your dependencies for a large multiproject solution and helps you to avoid version drift where multiple versions of the same package are used inside your solution. Remark: CPM works both in Visual Studio and in JetBrains Rider . Convert your .NET solution to CPM manually If you want to start using CPM for your existing solutions, there are a few steps you need to repeat for every project inside your solution: Go through all of the csproj files and copy the references into the centralised Directory.Packages.props file Remove all the versions from the package reference entries in the csproj files. Although not that hard to do, it would be nice if this can be done automatically. Auto

Before re-usability comes usability

Reuse remains one of the holy grails in software architecture. How wonderful is life if we can write a piece of code(component, module, service, you name it...) only once and then start to use it everywhere? It is not surprising that I see a lot of IT managers and architects always play the 'reusability' card no matter the context. Reusability is important. Period! The risks of reusability As a consequence hours and hours are spend in meetings, design discussions, alignment sessions between stakeholders… to find out how we can make what we are trying to build reusable. This not only overcomplicates our designs but can also lead to gold plating(“What if this happens?”, “Maybe we will need that somewhere in the future?”). Another effect of this unhealthy addication to reuse is that it starts to hinder usability. By building a UI component, a piece of code or a data model in such a way that it becomes re-usable, it also becomes more ‘generic’ or ‘general purpose. My you

.NET 7 - The StringSyntaxAttribute

With the release of .NET 7, a new attribute was introduced; the StringSyntaxAttribute . What does the StringSyntaxAttribute do? The StringSyntaxAttribute allows you to tag strings. It can be applied to fields, properties, and parameters and provides tools like Visual Studio with information about the nature of the string. The compiler will use this information to provide the correct syntax highlighting: In this release following string formats can be used out of the box (and it is possible to create custom ones): CompositeFormat: The syntax identifier for strings containing composite formats for string formatting. DateOnlyFormat: The syntax identifier for strings containing date format specifiers. DateTimeFormat: The syntax identifier for strings containing date and time format specifiers. EnumFormat: The syntax identifier for strings containing Enum format specifiers. GuidFormat: The syntax identifier for strings containing Guid format specifiers. J