Don't Do That, Do This: The .NET 6 Edition
Tags: csharp, dotnet
Published: 2021-12-08 15:15:46

---
title: Don't Do That, Do This: The .NET 6 Edition
published: true
date: 2021-12-08 14:28:47 UTC
tags: csharp, dotnet
canonical_url: https://www.daveabrock.com/2021/12/08/do-this-not-that-the-net-6-edition/
---

_This post is my annual contribution to the_ [_2021 C# Advent Calendar_](https://www.csadvent.christmas/)_. Please check out all the great posts from our wonderful community!_

Have you heard? .NET 6 [has officially arrived](https://devblogs.microsoft.com/dotnet/announcing-net-6/). There's a lot of good stuff: C# 10, performance improvements, Hot Reload, Minimal APIs, and much more. As is the case for most releases, a few big features tend to get most of the hype.

What about the features and improvements that don't knock _both_ your socks off but also help to make your daily development experience more productive? A lot of these "quality of life" features in .NET 6 can help by removing boilerplate and pain and can help you get to the point: shipping quality software.

As I get into the holiday spirit, consider this a stocking of sorts: just some random, little things that I hope you'll find enjoyable. (And despite the catchy title, there are always tradeoffs: do what works for you.)

## Don't chunk large collections manually, use the new LINQ API instead

When working with large collections of data, you likely need to work with smaller "chunks" of it—a big use case would be if you're getting a lot of data back from a third-party API. If there's no pagination set up and you have a bunch of data in memory, you'll probably want a way to "page" or split up the data.

What's a .NET developer to do? Do things the hard way. You'd probably do some logic to set a page size, check what page you're on and if there are any elements left, then update your code when you add pages to a collection. It'd be a series of `Take` and `Skip` LINQ calls, or maybe even an extension method, like [this one that's popular on Stack Overflow](https://stackoverflow.com/questions/438188/split-a-collection-into-n-parts-with-linq/438513#438513):

```csharp
static class LinqExtensions
{
    public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> list, int parts)
    {
        int i = 0;
        var splits = from item in list
                     group item by i++ % parts into part
                     select part.AsEnumerable();
        return splits;
    }
}
```

Don't do that, do this: use the new LINQ `Chunk` API. When we call `Chunk` on 200 elements, we'll get 20 lists of 10 elements each.

```csharp
int pageSize = 10;
IEnumerable<Employee[]> employeeChunk = employees.Chunk(pageSize);
```

## If you need just a date, don't use DateTime, use DateOnly

If you want to work with dates and times in .NET, you typically start with `DateTime`, `TimeSpan`, or `DateTimeOffset`. What if you only need to work with dates and only need a year, month, or day? In .NET 6, you can use a new `DateOnly` struct. (You can also use `TimeOnly`. I also promise this isn't the [start of a dating app](https://www.farmersonly.com/).)

We've all done something like this:

```csharp
var someDateTime = new DateTime(2014, 8, 24);
var justTheDate = someDateTime.ToShortDateString();

Console.WriteLine(someDateTime); // 8/24/2014 12:00:00 AM
Console.WriteLine(justTheDate); // "8/24/2014"
```

Don't do that, do this: use the `DateOnly` struct.

```csharp
var someDateTime = new DateOnly(2014, 8, 24);
Console.WriteLine(justTheDate); // 8/24/2014
```

There's [a lot more you can do with these](https://devblogs.microsoft.com/dotnet/date-time-and-time-zone-enhancements-in-net-6/), obviously, in terms of manipulation, calculation days between dates, and even combining with `DateTime`. Apart from being easier to work with, it also offers better type safety for just dates, a `Kind` property, and simpler serialization.

## Don't wire up a lot of custom code for logging HTTP requests, use the new logging middleware

Before .NET 6, logging HTTP requests wasn't hard but a little cumbersome. Here's one way: you'd probably have logic to read the request body, use your expert knowledge of ASP.NET Core middleware to pass the stream to whatever is next on the pipeline, and remember to register your middleware—all for a very common activity for any reasonably complex web application.

Don't do that, do this: use the new .NET 6 [HTTP Logging middleware](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-logging/?view=aspnetcore-6.0) to make your life easier.

Add this to your project's middleware:

```csharp
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseHttpLogging();

    // other stuff here, removed for brevity
}
```

Then, customize the logger as you see fit.

```csharp
public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpLogging(logging =>
    {
        logging.LoggingFields = HttpLoggingFields.All;
        logging.RequestHeaders.Add("X-Request-Header");
        logging.ResponseHeaders.Add("X-Response-Header");
        logging.RequestBodyLogLimit = 4096;
        logging.ResponseBodyLogLimit = 4096;
    });
}
```

You'll want to be watchful of what you log and how often you log it, but it's a great improvement.

## Don't use hacks to handle fatal Blazor Server exceptions, use the ErrorBoundary component

What happens when an unhandled exception in Blazor Server occurs? It's treated as fatal because "[the circuit is left in an undefined state which could lead to stability or security problems in Blazor Server](https://github.com/dotnet/aspnetcore/issues/30940#issue-831895900)." As a result, you might need to throw try/catch blocks all over the place as a preventive measure or encapsulate logic in JavaScript since no C# code runs after the unhandled exception.

Don't do that, do this: [use the new `ErrorBoundary` component](https://docs.microsoft.com/en-us/aspnet/core/blazor/fundamentals/handle-errors?view=aspnetcore-6.0). It isn't a global exception handler but will help deal with unpredictable behavior, especially with components you don't and can't control.

You can [see my article](https://www.telerik.com/blogs/work-unhandled-exceptions-gracefully-blazor-server-dotnet-6-error-boundaries) for the full treatment, but here's the gist: I can add an `ErrorBoundary` around the `@Body` of my default layout.

```html
<div class="main">
    <div class="content px-4">
        <ErrorBoundary>
            @Body
        </ErrorBoundary>
    </div>
</div>
```

Of course, you probably want to go further than a catch-all boundary. Here's me iterating through a list:

```html
<tbody>
    @foreach (var employee in Employees)
    {
        <ErrorBoundary @key="@board">
            <ChildContent>
                <tr>
                    <td>@employee.Id</td>
                    <td>@employee.FirstName</td>
                    <td>@employee.LastName</td>
                 </tr>
            </ChildContent>
            <ErrorContent>
                Sorry, I can't show @employee.Id because of an internal error.
            </ErrorContent>
        </ErrorBoundary>
    }
</tbody>
```

## Don't use Server.Kestrel verbose logging for just a few things, use the new subcategories

If I want to enable verbose logging for Kestrel, I'd previously need to use `Microsoft.AspNetCore.Server.Kestrel`. That still exists, but there are also [new subcategories](https://github.com/dotnet/aspnetcore/issues/30301) that should make things less expensive. (Computationally; you're still on the hook for holiday gifts, sorry.)

In addition to `Server.Kestrel`, we now have `Kestrel.BadRequests`, `Kestrel.Connections`, `Kestrel.Http2`, and `Kestrel.Http3`.

Let's say you only want to log bad requests. You'd normally do this:

```json
{
  "Logging": {
    "LogLevel": {
      "Microsoft.AspNetCore.Server.Kestrel": "Debug"
    }
  }
}
```

Don't do that. Do this:

```json
{
  "Logging": {
    "LogLevel": {
      "Microsoft.AspNetCore.Server.Kestrel.BadRequests": "Debug"
    }
  }
}
```

Is it the sexiest thing you'll read today? Unless you love logging more than I thought you did, probably not. But it'll definitely make working with Kestrel verbose logging much easier.

## Don't get lost in brackets, use C# 10 file-scoped namespaces instead 

C# 10 introduces the concept of [file-scoped namespaces](https://www.daveabrock.com/2021/10/05/csharp-10-file-scoped-namespaces/).

Here's a typical use of namespaces in C#:

```csharp
namespace SuperheroApp.Models
{
   public class Superhero
   {
      public string? FirstName { get; set; }
      public string? LastName { get; set; }
   }
}
```

Instead of downloading a bracket colorizer extension, do this instead:

```csharp
namespace SuperheroApp.Models;

public class Superhero
{
   public string? FirstName { get; set; }
   public string? LastName { get; set; }
}

```

Also, for the record (ha!), you can make this even simpler if you want to take advantage of [immutability and value-like behavior](https://www.daveabrock.com/2020/07/06/c-sharp-9-deep-dive-records/):

```csharp
namespace SuperheroApp.Models;

public record Superhero(string? FirstName, string LastName);
```

You should be aware of what you're getting with [positional parameters](https://www.daveabrock.com/2020/11/02/csharp-9-records-immutable-default/), but we can all agree this isn't your grandma's C# (and I'm here for _all_ of it, my apologies to grandma).

### Speaking of brackets ...

Since we're on the topic of brackets, C# 10 also introduces [e](https://www.daveabrock.com/2021/11/18/exploring-c-10-use-extended-property-patterns-to-easily-access-nested-properties/)[xtended property patterns](https://www.daveabrock.com/2021/11/18/exploring-c-10-use-extended-property-patterns-to-easily-access-nested-properties/).

You could use property patterns in a switch expression like this:

```csharp
public static int CalculateSuitSurcharge(Superhero hero) =>

        hero switch
        {
            { Suit: { Color: "Blue" } } => 100,
            { Suit: { Color: "Yellow" } } => 200,
            { Suit: { Color: "Red" } } => 300
            _ => 0
        };
```

Don't do that. Do this:

```csharp
public static int CalculateSuitSurcharge(Superhero hero) =>

        hero switch
        {
            { Suit.Color: "Blue" } => 100,
            { Suit.Color: "Yellow" } => 200,
            { Suit.Color: "Red" } => 300
            _ => 0
        };
```

## Wrapping up

I hope you enjoyed this post, and you learned a thing or two about how .NET 6 can make your developer life just a little bit easier. Have you tried any of these? Do you have others to share? Let me know in the comments [or on Twitter](https://twitter.com/daveabrock).