Posts about .NET
I've written about NuGet Central Package Management in the past, but since then there were some news in this field. Most importantly, the .NET Upgrade Assistant Visual Studio extension and command line tool has been extended with support for upgrading projects to Centralized Package Management.
I recently had to convince someone that the Entity Framework Core DbContext doesn't support running multiple queries in parallel even if the underlying connection does. Since I couldn't immediately find the documentation proving my point, I created a sample project which I decided to polish a little and share publicly.
Recently, I was troubleshooting some unexpected behavior of a REST service my team is maintaining: in its JSON response, the same numeric field sometimes included insignificant zeros after the decimal separator and sometimes it didn't. Further research revealed that the differences originated from another JSON document which served as the data source and manifested the same behavior. But we were still wondering why the insignificant zeros in the fractional part were preserved across deserializing the value and serializing it again.
JSON serialization allows a lot of flexibility, sometimes even too much, e.g., a field that can be serialized into two different JSON types, depending on its contents. It could be serialized as string. Or, it could be serialized as a number. To make deserialization work, I had to implement a custom JsonConverter.
As I wanted to make my side project more easily available to others by releasing it to GitHub and NuGet, I tried automating this step in GitHub Actions as well. It took me less time to get it working than expected.
The .NET SDK is accompanied by a large collection of code analysis rules, both for the C# language and for the SDK API usage. I firmly believe that for any long-lived project, it's worth the effort to configure the rules to match your preferences.
Authenticating with the GitHub API using a personal access token is perfectly fine if you're performing a one-time task for yourself. However, you're better off authenticating as a GitHub App if you're developing an automation for an organization and want it to do its job for a longer time.
Just recently, I received a bug report for an ASP.NET Core Web API application I'm maintaining because of incorrectly rendered schema for a response in the Swagger UI. The culprit ended up being an old version of Swagger UI used by an old version of Swashbuckle.
Typed clients are one of the recommended usage patterns for HttpClient in .NET. Although it's easy to set up, you can just as easily set it up incorrectly. I had to troubleshoot such cases more than once and the culprit has almost always been the same.
When you have many projects in your Visual Studio solution, it's not uncommon that the same NuGet packages are installed in multiple projects. In such a case, it's all too easy for the version of the same NuGet package in different projects to diverge. Once you notice this problem, you can quickly fix it with the Consolidate tab of the NuGet Package Manager in Visual Studio. But it would be even better if you could prevent it from happening in the first place.
I recently had a requirement for a Web API project I'm working on to be able to determine the exact commit used for a given build. Including a Git SHA in the build was the obvious choice. As I was looking for an easy way to do that, I learned that .NET 8 SDK already does it automatically: the AssemblyInformationalVersion has the SourceRevisionId property value appended which contains the Git SHA when building from a valid Git repository.
Just a few days ago I was troubleshooting some integration tests which turned out to be failing because of incorrectly set BaseAddress in the HttpClient class. This wasn't the first time a similar thing happened to me so I decided to write a blog post about it as a future reference for me, my team and anybody else who might find it useful.
Caching of NuGet packages can significantly speed up .NET builds in GitHub Actions, especially if your projects has many dependencies. The generic cache GitHub action used to be the only way to do that and I described how to configure it a while back in my article for DotNetCurry Magazine. However, recent versions of setup-dotnet GitHub action now have this functionality built in which makes the configuration even simpler.
The template I'm using for creating a new GitHub Actions workflow for .NET projects doesn't create any test and coverage reports, so that's usually the first thing I add to it. I've documented my approach in the past across two articles I've written for the DotNetCurry Magazine. But since the relevant instructions are interleaved with other topics and some details have changed since those articles were published, I decided to write this blog post with up-to-date information and focus only on this part of the workflow.
Although it's a good idea to avoid polling in your code if you can, there are still cases when it's necessary. While it's not too difficult to implement the polling loop manually, you can also use the Polly resilience library for that purpose.
When testing code that depends on HTTP calls, it's most common to mock the unit of the code that does the HTTP calls. In integration tests, however, you don't want to modify the application code. So you need to mock the server responding to the HTTP calls. WireMock.Net is a convenient tool to do that directly from test code.
There are many different ways for EF Core tools to get the connection string for the database to update using migrations. They are all listed in the documentation, but the order of priority in which they are used is unfortunately not very clear.
Old-school .NET console applications with a Program.Main method could easily be invoked from tests. You only needed to make the method and its containing class public. Then you could directly invoke it like any other method. That's not an option if you're using top-level statements because there's no Main method in your code to make publicly accessible.
You're probably used to standard extension methods for logging. If you use them in recent versions of .NET, you might encounter a warning if you have the analysis level for .NET analyzers set to at least latest recommended.
Verifying whether a call to ILogger has been made from a unit test is somewhat tricky because we're more often calling extension methods than instance methods, and those can't be directly verified. We need to verify the call to the underlying instance method.
Moq is my preferred mocking tool for .NET. Although it has rather good documentation, it doesn't include an example for what I needed, so it took me a while to actually get it working.
If you've used regular expressions a lot in .NET, you most likely already know that by using the Compiled option you can improve the run time performance a lot at the cost of higher initialization time. What you might not know is that since .NET 7 you can use a source generator instead to avoid that initialization cost.
In most projects, EF Core is only used with a single database provider. However, I'm currently working on a project, which requires us to transition from one database provider to another. And since we can't simply stop all other development until this process is complete, we need to support two different database providers in parallel, at least temporarily.
By default, the OpenAPI specification created by Swashbuckle for ASP.NET Core web API doesn't include the descriptions for endpoints and models from XML comments. There are step-by-step instructions how to add them in the documentation, but even then there will be no descriptions for models from other assemblies.
Extension methods are a great way to extend classes you don't own with what looks like an instance method. Therefore, you usually don't need to create extension methods for a class from the same assembly because you could simply add the same code to that class as an instance method. However, not everything you can do with an extension method can also be done with an instance method.
In my recent dealings with MySQL, I learned that some connection string options affect the behavior to such an extent that the code will break unless they are set correctly. To prevent the application failing because somebody configured the connection string wrong, you can make sure in code that the selected options are set correctly.
Using Entity Framework Core for loading large amounts of data into database is not very efficient. The bulk operations from the EFCore.BulkExtensions NuGet package can help in such scenarios. Unfortunately, not all of them work (yet) for all database types.
In the sample project for my previous blog post, I noticed that every time I ran my test, its code was executed twice. At first, I thought that I had a bug in my code, but quickly dismissed this option. After further investigation, I finally attributed the strange behavior to the Fine Code Coverage Visual Studio extension.
I've been recently involved in migrating a .NET project from Microsoft SQL Server to MySQL. While most of it went pretty smoothly, we did encounter some challenges with GUID/UUID values.
The MemoryCache class is a common choice for in-memory caching in ASP.NET Core and .NET applications in general. Although it can work well in many scenarios, it's good to know its potential downsides. By design, it allows the factory method to fetch the value multiple times in case of a cache miss.
Asynchronous streams (i.e., the IAsyncEnumerable interface) were one of the new features in C# 8. However, it didn't get as much attention as some others. Even today, the feature is rarely used and not well known among C# developers, although it can make the code faster and easier to understand in some cases.
In a previous post, I wrote about the built-in log correlation features for ASP.NET Core when logging to Application Insights. But what if you want to log elsewhere or want more control over the correlation ID? A custom middleware could be all you need.
Glob patterns are a cross-platform standard approach for specifying sets of filenames. There is no built-in support for them in the base class library, but you can choose from multiple NuGet packages.
If you're hosting your ASP.NET Core application in Azure, you're most likely collecting your logs in Application Insights. Make sure you configure the logging in your application correctly to take advantage of built-in support for per-request log correlation.
After you create a new .NET 8 project, you'll soon notice many new diagnostics being enabled by default. If you're using string interpolation in your logging calls, it will now result in code suggestions in your error list.
To authenticate to an OAuth identity provider from a desktop app, the authorization code flow should be used. To implement it, you will have to host a web view control in your application.
Mocking HttpClient in .NET isn't difficult. But if you haven't done it before, it's not obvious how to approach it, since the class has no interface or virtual methods. What you should mock, is the protected abstract SendAsync method of the HttpMessageHandler class, which can be passed to HttpClient as a constructor parameter.
Usually, before manipulating JSON inputs, you first deserialize them into strongly typed objects that match their structure. However, that might not always be possible. Recently, I had to combine multiple JSON inputs into a single JSON array, without any knowledge of the input JSON structure.
The dependency injection framework that is built into the modern .NET works well enough to satisfy the needs of most projects. However, it's not as feature-rich as the most popular 3rd party libraries. One of the features that was missing before .NET 8 was the ability to register multiple implementations of the same interface and have the ability to specify which one should be injected.
Mocking frameworks can be used not only to mock methods, but also to verify whether those mocked methods have actually been called. The latter is sometimes called interaction testing and is particularly useful when you want to test that specific calls to an external API have been called. Of course, Moq also supports such setup verification.
In large projects, service registration code for dependency injection can grow rather large. Forgetting to register a newly added dependency will break your application at the point of instantiating a class (transitively) requiring it. It's even more likely that this will happen to you if you need to register a dependency in multiple places (e.g., for multiple projects) and don't have tests for every one of them.
During the upgrade of an ASP.NET Core Web API application from .NET Core 3.1 to .NET 6 I stumbled across a breaking change that only manifested itself at run time despite a pretty good test coverage.
After creating a working dev container configuration for an ASP.NET Core with Angular project, I wanted to also try it out with GitHub Codespaces. I had to do additional changes to the configuration to get it working.
I was recently involved in updating a bunch of .NET projects deployed to Azure from older versions to .NET 6. Among them, there was also an Azure Function app. To my surprise, unlike Azure Web App services, not everything could be reconfigured through Azure Portal.
For simple projects with a single technology stack, you're likely to find a dev container template preconfigured with everything you need. That's what happened to me when I created my first dev container. For larger projects with more than one technology stack, more configuration will be needed.
I couldn't find a complete guide for deploying an AWS Lambda function in .NET from a local machine. I'm publishing my notes on the subject for future reference and anyone else interested.
After I learned about JsonStringEnumMemberConverter, I wanted to use it for an enum in a large project I was working with, but to my surprise it didn't seem to have any effect on the serialization.
As I was recently updating an old .NET Core 3.1 project to .NET 6, I encountered an unexpected breaking change. I couldn't find any documentation about it, even after I already knew about it. Fortunately, I noticed it before deploying the application to production thanks to the test coverage.
When serializing enums to JSON, it's usually better to serialize them as descriptive strings than incomprehensible magic numbers. Most of the time, it's good enough to simply use the names of enum members for this purpose. However, these must follow the rules for identifier names in C#, so they might be too restrictive if you need to use specific string values because of interoperability with other systems.
After I updated my copy of Visual Studio 2022 to the latest version 17.6, I couldn't run the tests from the Test Explorer anymore that worked just fine in version 17.5. I had similar experience in the past, so I immediately suspected that the problems were related to the versions of test-related NuGet packages in my project.
When I updated MSTest from v2 to v3 in one of my projects, some tests started failing. It was because of a breaking change in MS Test V3 that caused the TestContext.DeploymentDirectory property to return a different path.
I recently helped troubleshoot a WPF application that was causing an unhandled exception. I thought the process of identifying and fixing the problem might be useful to others and decided to describe it in this post.
Data-driven tests are great for repeating the same unit tests with many different inputs. However, a test from a project I worked on failed on multiple test cases because a double value was incorrectly handled as a decimal.
The recently disclosed vulnerability in Newtonsoft.Json prompted me to take a closer look at the tools available in the .NET ecosystem for identifying referenced packages with known vulnerabilities.
In most cases, you do not want to write tests for non-public methods, because that would make the tests dependent on the internal implementation of a class. But there are always exceptions.
When you write unit tests, make sure not only that they succeed if the tested code works as expected, but also that they fail if the code does not work as expected. Otherwise, these tests will give you a false sense of confidence in your code.
Since .NET 5, the coverlet.collector NuGet package is pre-installed in the test project templates, which can generate code coverage reports when the tests are executed. Let us take a look at how you can use this in your code editor.
It pays in the long run to learn about the various capabilities of unit testing frameworks and use them to make unit testing code more maintainable. Let us go through the process of refactoring a set of copy-pasted tests into a single parameterized, i.e. data-driven test.
When I recently needed to update some existing unit tests, I noticed that many asynchronous tests were using async void in their signature. My first instinct was to fix them by using async Task instead, because that surely meant they were broken and would not detect failures correctly. But before I did that, I experimented a bit, and as far as I could tell, the tests worked as expected, correctly detecting failed assertions and unexpected exceptions. I decided to do some more research on the subject.
The project properties window has been redesigned in Visual Studio 2022. But not only the appearance has changed. For at least some options, the effect of the changes in the project properties window has also changed. Let us take a look at how the behavior of the Allow unsafe code build option has changed.
The new console application template in .NET 6 is as minimal as possible thanks to top-level statements. That's great for simple applications, but what if you want to create a large console application with a sophisticated command-line interface?
NullReferenceException is probably one of the most common exceptions in .NET. It is thrown whenever you try to access a member of a reference type that is currently set to the value null. With the nullable reference types introduced in C# 8, the compiler can now warn you if you try to do this, so you can add a null check to prevent the exception from being thrown. Null checking code is simple, but very repetitive and potentially error-prone.
.NET makes it really easy to scrape some data from a public website. You can use HttpClient to download the web page. The best library for parsing the HTML is probably AngleSharp, but that's not the topic of this post. Instead, I'll focus on what to do if the web page is not public and you need to log in first. Typically, you will then need to submit the login form programmatically and use the cookies from the response in future requests.
Recently I solved a problem with a POST request that failed with a 405 error (Method Not Allowed), even though there was only a POST endpoint at the requested URL. After solving the problem, I found it interesting enough to reproduce it and wrote a post about it.
Mocks can be a helpful tool for replacing external dependencies in unit tests. However, caution is required when you embark on that route or you could end up with tests that don't really test your code under test.
ASP.NET Core applications are already set up with support for reading configuration files and switching between different environments. You get none of that when you create a new .NET console application. Fortunately, you can still take advantage of the same NuGet packages add similar support with minimum amount of setup code.
With the new System.Text.Json built into .NET Core, JSON serialization can now be performed without the Json.NET library. However, there are differences between the two libraries once you go beyond the basics. For example, support for serializing and deserializing polymorphic objects is limited in the new library.
Since the release of Roslyn, the complete C# compiler pipeline is available as a NuGet package and we can include it in our own application. I was wondering how difficult it would be to use it to compile some C# source code into an executable and run it.
Yesterday the NT Conference 2019 concluded in Portorož. This year I had three sessions there. On Tuesday, I talked about the new language features in C# 8. On Wednesday, I repeated my session about application architecture from this year's Global Azure Bootcamp. My final session on Thursday was about global tools in .NET Core.
Since this week, The Absolutely Awesome Book on C# and .NET is finally available for order in its final form: in all eBook formats and with the accompanying source code.
Tuples, as added to C# 7, can be a nice alternative to anonymous types in LINQ when you only want to return a subset of values from the queried type. Before tuples, this was only possible by creating an anonymous type in the Select method. Now you can create a tuple instead. However, if you try to do that with EF Core, the code won't compile. How come?
Cyclomatic complexity is a simple code metric, commonly used to identify complex methods which are difficult to maintain and therefore good candidates for refactoring. It is one of the five code metrics built into Visual Studio 2017, but it isn't available for .NET Core and .NET Standard projects. Let's look at third party extensions which you can use instead.
It's the week of NT Conference 2018. I had two sessions this year. On Tuesday, I talked about a selection of common C# gotchas which can surprise even an experienced C# developer. In my second session, I explained the benefits of continuous testing and showed how to configure it for a .NET Core project in Visual Studio 2017 and Visual Studio Code.
It's April again and last Saturday it was time for the annual Global Azure Bootcamp event. The Slovenian one was taking place at the local Microsoft offices. In my session, I explained how to configure Visual Studio Code to improve the experience of .NET Core development as much as possible.
The last Slovenian Developers User Group meeting before the summer break consisted of the two most popular sessions from Microsoft NT Conference, as voted by the user group members.
At the beginning of this week the traditional NT Conference was taking place in Portorož. I had my only session this year on Monday, where I talked about .NET Core and .NET Standard.
This week the second community organized Cancel conference was taking place in Ljubljana. It spanned over two days. Thursday was the main conference day with 20 sessions grouped in 4 tracks. On Wednesday afternoon preconf was organized at the premises of Microsoft Slovenia. I had my sessions on both days.