Posts

2024 in Retrospective

This year was very important to me, professionally. I changed job , wrote 18 + 12 posts (in the old and the new blog ) - which, accidentally, means I got a new blog after 15 years with the old one -, went to some cool Microsoft events, and, finally, was awarded as Microsoft MVP once again ! Some things didn't work out exactly as I was expecting them to, but, in general, it was a very positive year. More news coming soon! I'd like to wish you all an excellent 2025!

.NET Cancellation Tokens

Introduction Cancellation tokens in .NET were introduced as part of the  .NET 4 Cancellation Framework . Essentially, it is a standard, cooperative, way to request for the cancellation of the execution of an operation. By cooperative it means that the code that uses it must abide to some rules, as opposed to the cancellation just stopping (killing) the execution. One example of cancellation is, on a web app, when the client closes the connection while the server is performing some long operation. In cases such as this, we may want to abort the operation, as we are not sending the results anywhere (or not, as we shall see). Because of this, ASP.NET Core allows us to add a parameter of type  CancellationToken  to our asynchronous actions, it is automatically associated with the client and is therefore signalled when the client connection is closed. A  CancellationToken  is, essentially, behind the scenes, a ManualResetEvent . Throughout this article I will either ...

What's New in .NET 9 and C# 13

Introduction .NET 9 and C# 13 have been released some days ago , so it's time for my own resume of the new features. There are tons of improvements, quite a few related to performance, so, beware, if you want the whole thing, you should read the official documentation , these are just my personal choices! Semi-Auto Properties C# 13 introduced a new (experimental as of now, you need to turn on the preview language features for the project) keyword called field , which can be used, in auto-properties , to access the auto-generated field.  To set the language version to preview , add this to your .csproj file: <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net9.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> <LangVersion>preview</LangVersion> </PropertyGroup> And to make it work: public DateTime Date { get { return field; } ...

MVP Again

Yesterday, December 1st, I was extremely excited to find out that I had been nominated as Microsoft Most Valuable Professional (MVP)  once again! For those of you who are not familiar with this, it is an award granted by Microsoft to some individuals who somehow are relevant to the development community. You can read more about the MVP programme  here . I had previously been an MVP from 2015 until mid 2019, but then I wasn't renewed. This time, my friend and Visual Studio extensions legend Erik Ejlskov Jensen  nominated me, and I was accepted! It is an honour and a privilege to be again part of this exclusive programme, amongst such brilliant people! Besides  Erik , I also need to thank Cristina Gonzalez Herrero , my friend and MVP Community Program Manager for Southern Europe, for reviewing my nomination, and accepting it. Muchas gracias, Cristina! ;-) Please let me know if you want to learn more or discuss this or any other subject. See you around!

Audit Trails in EF Core

Introduction Audit trails is a common feature in database systems. Essentially, it's about knowing, for every table (or some selected ones), who created/updated each record, and when the creates/updates happened. It can also be useful to store the previous values too. Some regulations, such as SOX , require this for compliance. There are some libraries that can do this automatically in EF Core , and there's also the Change Data Capture in SQL Server (and possibly other databases too), of which I wrote about some time ago, but, hey, I wanted to write my own, so here is EFAuditable , my library for doing audit trails in EF Core. This one is designed with some extensibility in mind, so, please, read on. Scenarios EFAuditable  allows the following scenarios: Entities marked for auditing will have the audit columns added and persisted automatically to the database, on the same table Entities marked for history keeping will have their old values (in the case of updates or deletes) ...

Domain Events with .NET - Events Dispatcher Executor

Introduction You may remember my Domain Events with .NET post and library . I recently made some changes , and now, some more, of which I'll talk here. I'm now introducing a new concept: A  dispatcher executor  is a class that is responsible for calling subscribers when invoked by a dispatcher Events Dispatcher Executor Essentially, it's a new interface/abstraction,  IEventsDispatcherExecutor . This interface - or, rather, one implementation of it - is the actual responsible for calling a subscription inside the  IEventsDispatcher  implementation, so all existing implementations were modified to use it. This allows, for example, a retry strategy. I included a simple one, which can be applied by using the WithRetries extension method: builder.Services.AddDomainEventsFromAssembly(typeof(Program).Assembly) .WithRetries(3, TimeSpan.FromSeconds(3)); And this is it. In the case of any exception while invoking the subscription, the executor will retry a number of...

ASP.NET Core Pitfalls – Posting a String

This is another post on my ASP.NET Core pitfalls series . It is actually related to this one  ASP.NET Core Pitfalls – Null Models in Post Requests . What happens if you try to submit a string containing JSON as a POST? I mean, you always submit strings, but this time you don't want for it to be parsed into some class. Like this: [HttpPost] public IActionResult PostString([FromBody] string json) { ... } You may be surprised to find out that this fails with a HTTP 415 Unsupported Media Type . Now, you might be tempted to add an [Consumes] attribute to it, such as: [HttpPost] [Consumes("application/json")] public IActionResult PostString([FromBody] string json) { ... } And this will actually work! The problem is, or could be, that it requires the sender to send the appropriate Content-Type header (" application/json "). Another, better, solution is to just read the string from the from the request stream: [HttpPost] public IActionResult PostString() { using v...

Named HttpClient Registrations

Introduction You're most likely familiar with HttpClient and its recommended usage , which involves calling one of the overloads of AddHttpClient . One thing that you may or may not have noticed is, even though you call the overload that takes a name for the client, it is not registered in the dependency injection (DI) container as such. So I went out to fix this! So, what we want is that any named clients can be also registered with the DI container, which will allow us to retrieve them by the service type and key: var googleClient = serviceProvider.GetRequiredKeyedService<HttpClient>("Google"); or: public IActionResult Index([FromKeyedServices("Google")] HttpClient googleClient) { ... } So, as of now, the only way to obtain the named client is by using  IHttpClientFactory 's CreateClient method: var googleClient = serviceProvider.GetRequiredService<IHttpClientFactory>().CreateClient("Google"); Which is fine, but just takes some extr...

A Search Proxy in .NET

Introduction We all use Internet search. Nowadays, bookmarks have become somewhat outdated, as the modern search engines are so good at finding what we want, that they have become somewhat obsolete. But, what if we need to perform a search in code? We can obviously send an HTTP request to our search engine of choice and then parse the result, but it would be useful if there was a library that could do it for us. And this is how Search.NET was born! Concepts First, let's define a contract for a search proxy in .NET. A concrete proxy implementation will be specific to a search engine, such as Google , or Bing , but the contract will be the same. Here is what I propose, a contract named ISearch : public interface ISearch {     Task<SearchResult> Search(string query, CancellationToken cancellationToken = default); Task<SearchResult> Search(string query, QueryOptions options, CancellationToken cancellationToken = default); } As you can see, it has essentially o...