Skip to main content

Posts

Showing posts from 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

Url.ActionLink() is not thread-safe

I have an API that allows users to upload documents. To optimize the performance I save the documents to the database in parallel. After uploading has completed I return a list of URI's pointing to the document locations. Here is what the code looks like: As you can see in the code above, I combine a Task.WhenAll with a local function . Nothing special. However when I executed this code under high load, I started to get errors back from the API. A look at the logs, showed the following exception: Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: chunkLength at System.Text.StringBuilder.ToString()   at Microsoft.AspNetCore.Mvc.Routing.UrlHelperBase.GenerateUrl(String protocol, String host, String path)   at Microsoft.AspNetCore.Mvc.Routing.EndpointRoutingUrlHelper.Action(UrlActionContext urlActionContext)   at Microsoft.AspNetCore.Mvc.UrlHelperExtensions.ActionLink(IUrlHelper helper, String action, String control

TDD, where did it all go wrong?

Every year, a new generation of developers start their career. And every year, I see these new developers struggling with writing tests. And if you dare to go one step further, and introduce them to Test Driven Development, they get even more confused. Don't misunderstand me, they are quite fast in understanding the mechanics of the testing frameworks(MsTest, Xunit, ...). But it turns out that is really hard to write good, maintainable tests that help to move forward instead of becoming a bottleneck. One of the reasons this is such a problem, is that what is now described as Test Driven Development is not aligned with the original intention. Ian Cooper has a great talk exactly about this issue: Ian Cooper reminds what was Kent's original proposition on TDD, what misunderstandings occurred along the way and suggests a better approach to TDD, one that supports development rather impeding it. There are 2 key elements of his talk, that I think are most important:

Using Event Counters with Application Insights

When adding the Application Insights SDK to your application, a set of Performance Counters is tracked by default. This is the list of default counters for ASP.NET web applications: % Process\Processor Time % Process\Processor Time Normalized Memory\Available Bytes ASP.NET Requests/Sec .NET CLR Exceptions Thrown / sec ASP.NET ApplicationsRequest Execution Time Process\Private Bytes Process\IO Data Bytes/sec ASP.NET Applications\Requests In Application Queue Processor(_Total)\% Processor Time However Performance Counters are a windows only feature. With .NET being cross-platform, is there a solution that works on both Windows and Linux? Of course there is! (Otherwise I wouldn’t be writing this blog post). Collecting EventCounters with Application Insights The documentation has the following to say about EventCounters: EventCounter is .NET/.NET Core mechanism to publish and consume counters or statistics. EventCounters are suppor

EF Core 7 - Handling deletes

I’m still catching up on all the improvements that come with the release of .NET 7. One thing I noticed is a nice new feature in EF Core 7 . Before EF Core 7 when you want to delete an entity you had to fetch it first. With the new ExecuteDelete (and ExecuteUpdate ) method you can execute delete commands (and update commands) directly in the database. Executing the code above will result in the following query: As you can see, it generates a SQL statement to delete the entities that match the condition. Exactly what you would expect and without the overhead of loading the entities in memory first. Nice! Remark: EF Core 7 can be used with .NET 6. So you can start using this feature without having to upgrade to .NET 7 first. Also keep the following in mind when using the ExecuteDelete method: The specific changes to make must be specified explicitly; they are not automatically detected by EF Core. Any tracked entities will not be kept in sync. Additional comma

Monitor your application using Event Counters - Part III

I'm building a data pipeline using TPL Dataflow to migrate data from a database to an external API. As this data pipeline could run for a long time, I was looking for a good way to monitor the progress. This turned out to be a perfect use case for Event Counters . So far we have seen how to create a simple EventCounter using a PollingCounter and how to read out its value using the dotnet-counters global tool. The PollingCounter uses a callback to determine the value that is reported. With each time interval, the user provided callback function is invoked and the return value is used as the counter value. This allows us to manage and track the number of migrated documents ourselves. Let’s continue today and have a look at how we can use some of the other counters to improve our metrics. Tracking the migration rate using the IncrementingPollingCounter We are already tracking the number of migrated documents. Wouldn’t it be nice to also track the number of documents that