Discover the New ASP.NET Core Features in .NET 7!
Tags: csharp, dotnet, news, programming
Published: 2022-08-09 06:54:00

It is no news that Microsoft is working very hard on improving and bringing new features to the .NET framework or to its C# programming language. This time **Microsoft is targeting web development** and is **focusing on ASP.NET Core**, which will apparently come hand in hand with the .NET 7 version.

Some time ago Microsoft released Preview 1 of ASP.NET Core on .NET 7 and the amount of new features is great, so let’s see the new features!

---

## New Minimal API Improvements

The first of the new features will bring improvements in [minimal APIs](https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-net-7-preview-1/#minimal-api-improvements), especially in `IFormFile` and `IFormCollection`. With this new improvement you will be able to use `IFormFile`and `IFormCollection` to [handle and manage file uploads](https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-net-7-preview-1/#iformfile-and-iformfilecollection-support) in a much easier way.

Microsoft warns that if you want to use these new functions with authentication, anti-forgery is required, but so far Microsoft has not implemented such support. However, they reassure us that it is on the roadmap of .NET 7.

Support for such requests with client certificates or cookie headers is currently inactive. Let’s take a look at the [example provided by Microsoft](https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-net-7-preview-1/#iformfile-and-iformfilecollection-support) to see this new ASP.NET Core feature in action:

```csharp
app.MapPost("/upload", async(IFormFile file) =>
{
    using var stream = System.IO.File.OpenWrite("upload.txt");
    await file.CopyToAsync(stream); 
});

app.MapPost("/upload", async (IFormFileCollection myFiles) => { ... });
```

And that’s not all, we still have [more minimal API improvements](https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-net-7-preview-1/#bind-the-request-body-as-a-stream-or-pipereader).

The next new enhancement for the minimal APIs in ASP.NET Core comes for `Steam` and `PipeRider`.

To understand in what kind of scenario these new minimal APIs would be used, let’s imagine that we need to store data in a blob storage or queue it in some queue provider like Azure. In this case we can use `Steam` and `PipeRider` to bind the body of a request and later process it in the cloud. Let’s look at [Microsoft’s example](https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-net-7-preview-1/#bind-the-request-body-as-a-stream-or-pipereader):

```csharp
app.MapPost("v1/feeds", async (QueueClient queueClient, Stream body, CancellationToken cancellationToken) =>
{
    await queueClient.CreateIfNotExistsAsync(cancellationToken: cancellationToken);
    await queueClient.SendMessageAsync(await BinaryData.FromStreamAsync(body), cancellationToken: cancellationToken);
});
```

However, Microsoft warns us three details to achieve a correct functioning of these minimal APIs:

-   The `Stream` will always be the same object as `HttpRequest.Body` when ingesting any type of data.
-   The `Stream` cannot be read again more than once (_not rewindable_) since by default the request body is not stored in the buffer.
-   As the underlying buffers will end up being reused and discarded, both `Stream` and `PipeRider` cannot be used outside of the action handler.

The last improvement in the minimal APIs that Microsoft brings in this Preview 1 is about JSON configuration. Through `ConfigureRouteHandlerJsonOptions` we will be able to manually configure the options and settings of the minimal API endpoints using JSON.

This improvement has been introduced mainly, as Microsoft says, to avoid confusion with `Microsoft.AspNetCore.Mvc.JsonOptions`. Let’s see the example provided by Microsoft:

```csharp
var builder = WebApplication.CreateBuilder(args);
builder.Services.ConfigureRouteHandlerJsonOptions(options =>
{
    //Ignore Cycles
    options.SerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles; 
});
```

If you want to know more about this feature, I recommend you, as always, to consult the original source: [Minimal API improvements](https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-net-7-preview-1/#minimal-api-improvements)

---

## New client source generator for SignalR

This is the next new feature that ASP.NET Core will bring in .NET 7. This new source code generator for [SignalR](https://docs.microsoft.com/en-us/aspnet/signalr/overview/getting-started/introduction-to-signalr) introduced by Microsoft has the ability to generate code (_both sending and receiving_) strongly typed based on developer-defined interfaces.

This especially applies to SignalR hub interfaces, there would be no need to use them in loosely-typed methods, we now have the option to reuse them in the client. At the same time, there is the possibility of implementing an interface that contains the methods and at the same time the client can take advantage of that interface to call any method that is part of the hub.

The good thing is that Microsoft has let us see the use and operation of this new SignalR generator. Let’s see [how Microsoft uses it](https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-net-7-preview-1/#signalr-client-source-generator):

-   First you need to add a reference to `Microsoft.AspNetCore.SignalR.Client.SourceGenerator` .
-   Then the following classes must be added to the project: `HubClientProxyAttribute` and `HubServerProxyAttribute` :

```csharp
[AttributeUsage(AttributeTargets.Method)]
internal class HubServerProxyAttribute : Attribute
{
}

[AttributeUsage(AttributeTargets.Method)]
internal class HubClientProxyAttribute : Attribute
{
}
```

- The next step is to add a static partial class and write the following static partial methods together with the attributes `HubServerProxy` and `HubClientProxy` in this way:

```csharp
internal static partial class MyCustomExtensions
{
    [HubClientProxy]
    public static partial IDisposable ClientRegistration<T>(this HubConnection connection, T provider);

    [HubServerProxy]
    public static partial T ServerProxy<T>(this HubConnection connection);
}
```

- And finally, we would use the partial methods and that’s it:

```csharp
public interface IServerHub
{
    Task SendMessage(string message);
    Task<int> Echo(int i);
}

public interface IClient
{
    Task ReceiveMessage(string message);
}

public class Client : IClient
{
    // Equivalent to HubConnection.On("ReceiveMessage", (message) => {});
    Task ReceiveMessage(string message)
    {
        return Task.CompletedTask;
    }
}

HubConnection connection = new HubConnectionBuilder().WithUrl("...").Build();
var stronglyTypedConnection = connection.ServerProxy<IServerHub>();
var registrations = connection.ClientRegistration<IClient>(new Client());

await stronglyTypedConnection.SendMessage("Hello world");
var echo = await stronglyTypedConnection.Echo(10);
```

That’s it, that’s how easy it is to use the new SignalR client source generator.

If you want to know more about this feature, I recommend you, as always, to consult the original source: [SignalR client source generator](https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-net-7-preview-1/#signalr-client-source-generator)

---

## Razor Pages and MVC views with nullable models

We continue with the next improvement brought by Microsoft. This time they have focused on improving the user experience of the checks and for this, they have implemented the [nullable view](https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-net-7-preview-1/#support-for-nullable-models-in-mvc-views-and-razor-pages) for the checks that are made of null state of any ASP.NET Core application. In this case this is the [example that Microsoft provides us](https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-net-7-preview-1/#support-for-nullable-models-in-mvc-views-and-razor-pages):

```csharp
@model Product?
```

Unfortunately there are no further examples or use cases for this new feature. Hopefully Microsoft will continue to release new features and talk more about the ones already revealed.

----

## Validate errors with JSON property names

Thanks to this new ASP.NET feature we will be able to manually configure with “[SystemTextJsonValidationMetadataProvider](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.modelbinding.metadata.systemtextjsonvalidationmetadataprovider?view=aspnetcore-7.0)” the validation to use the JSON property names.

Previously as the names of the properties that a model has, commonly were implementation details, managing them from a single page application was difficult. Let’s check the following [example](https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-net-7-preview-1/#use-json-property-names-in-validation-errors) implementing this new feature:

```csharp
services.AddControllers(options =>
{
    options.ModelMetadataDetailsProviders.Add(new SystemTextJsonValidationMetadataProvider())
});
```

If you want to know more about this feature, I recommend you, as always, to consult the original source: [Use JSON property names in validation errors](https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-net-7-preview-1/#use-json-property-names-in-validation-errors)

---

## New dotnet watch console output

Let’s move on to my favorite feature, now Microsoft has worked on achieving a much cleaner console output of [dotnet watch](https://docs.microsoft.com/en-us/aspnet/core/tutorials/dotnet-watch?view=aspnetcore-6.0), getting a better logout and a few emojis.

Personally I have nothing to add to this feature, just look at [Microsoft’s example](https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-net-7-preview-1/#improved-console-output-for-dotnet-watch):

```csharp
C:BlazorApp> dotnet watch
dotnet watch 🔥 Hot reload enabled. For a list of supported edits, see https://aka.ms/dotnet/hot-reload.
  💡 Press "Ctrl + R" to restart.
dotnet watch 🔧 Building...
  Determining projects to restore...
  All projects are up-to-date for restore.
  You are using a preview version of .NET. See: https://aka.ms/dotnet-support-policy
  BlazorApp -> C:UsersdarothDesktopBlazorAppbinDebugnet7.0BlazorApp.dll
dotnet watch 🚀 Started
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: https://localhost:7148
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5041
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: C:UsersdarothDesktopBlazorApp
dotnet watch ⌚ File changed: .PagesIndex.razor.
dotnet watch 🔥 Hot reload of changes succeeded.
info: Microsoft.Hosting.Lifetime[0]
      Application is shutting down...
dotnet watch 🛑 Shutdown requested. Press Ctrl+C again to force exit.
```

I like what I see, do you like it?

If you want to know more about this feature, I recommend you, as always, to consult the original source: [Improved console output for dotnet watch](https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-net-7-preview-1/#improved-console-output-for-dotnet-watch).

---

## Injection services in Blazor

[Injecting services into Blazor](https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-net-7-preview-1/#inject-services-into-custom-validation-attributes-in-blazor)? attributes Yes, thanks to this improvement you will be able to inject almost any type of service into custom validation attributes. To do so, the `ValidationContext` will be configured by Blazor to be used as a service provider. Let’s see the following [Microsoft example](https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-net-7-preview-1/#inject-services-into-custom-validation-attributes-in-blazor):

```csharp
public class SaladChefValidatorAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var saladChef = validationContext.GetRequiredService<SaladChef>();
        if (saladChef.ThingsYouCanPutInASalad.Contains(value.ToString()))
        {
            return ValidationResult.Success;
        }
        return new ValidationResult("You should not put that in a salad!");
    }
}

// Simple class configured as a service for dependency injection
public class SaladChef
{
    public string[] ThingsYouCanPutInASalad = { "Strawberries", "Pineapple", "Honeydew", "Watermelon", "Grapes" };
}
```

If you want to know more about this feature, I recommend you, as always, to consult the original source: [Inject services into custom validation attributes in Blazor](https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-net-7-preview-1/#inject-services-into-custom-validation-attributes-in-blazor)

At the moment we are still waiting for any new news that may come out from Microsoft. What we do know is that it is currently focusing mainly on performance, Blazor, Razor, HTTP/3, MVC and some other things.

What can Microsoft bring us in the coming months? What will surprise us? Only Microsoft knows :)