In the ever-evolving world of web development, staying updated with the latest features and enhancements is crucial. ASP.NET Core, a robust and versatile framework for building modern web applications, is no exception. With each new release, it brings a host of improvements and new features that make web development more efficient and enjoyable. In this article, we will delve into the latest features introduced in ASP.NET Core and explore how they can benefit your development process.
Latest Features in ASP.NET Core
1. Constructor Injection in Blazor
Constructor Injection in Blazor is a technique where the dependencies of a class (or a Razor component in the case of Blazor) are supplied via its constructor.
In Blazor, services (like NavigationManager, HttpClient, etc.) can be injected into Razor components using this technique. When an instance of the component is created, Blazor’s dependency injection (DI) system provides instances of the services specified in the component’s constructor.
Here’s a simple example:
public partial class ExampleComponent
{
protected NavigationManager Navigation { get; }
public ExampleComponent(NavigationManager navigation)
{
Navigation = navigation;
}
}
In this example, NavigationManager is a service injected into ExampleComponent via its constructor. The instance of NavigationManager is then assigned to the Navigation property to be used within the component. This is a common pattern for service injection in Blazor applications.
This technique helps to achieve loose coupling and better testability in your Blazor applications. It’s part of a broader set of techniques known as Dependency Injection (DI), a design pattern widely used in modern software development. It allows for better modularity, flexibility, and testing in applications.
Using constructor injection, you can easily swap out dependencies for testing or change them as your application evolves without modifying your components or classes. This makes your code more maintainable and robust.
2. WebSocket compression for Interactive Server components
WebSocket compression is a feature in Interactive Server components in ASP.NET Core that allows data to be compressed before it’s sent over a WebSocket connection. This can significantly reduce the amount of data that needs to be transferred, leading to improved performance, especially in scenarios where network bandwidth is a limiting factor.
By default, Interactive Server components enable compression for WebSocket connections. This means that any data sent over a WebSocket connection is automatically compressed by the server before it’s sent, and then decompressed by the client after it’s received.
However, enabling compression can increase the vulnerability of the app to certain types of attacks, such as CRIME (Compression Ratio Info-leak Made Easy) and BREACH (Browser Reconnaissance and Exfiltration via Adaptive Compression of Hypertext). These are security exploits against the HTTPS protocol which utilizes data compression to extract secrets from encrypted connections.
To mitigate these risks, compression can be disabled by setting ConfigureWebSocketOptions to null:
.AddInteractiveServerRenderMode(o => o.ConfigureWebSocketOptions = null)
In addition to WebSocket compression, Interactive Server components also set a frame-ancestors Content Security Policy (CSP) directive to 'self' by default. This directive controls whether the app can be embedded in an <iframe> of the origin from which the app is served.
A stricter frame-ancestors CSP can be configured with a value of 'none', which prevents browsers from embedding the app into any <iframe>, even if WebSocket compression is allowed:
.AddInteractiveServerRenderMode(o => o.ContentSecurityFrameAncestorsPolicy = "'none'")
These features provide developers more control over the security and performance of their Blazor applications when using Interactive Server components.
3. Polymorphic support in SignalR Hubs
In the context of SignalR Hubs in ASP.NET Core, polymorphic support means that Hub methods can accept parameters of a base class type, and then behave differently depending on the actual derived class of the object passed in.
It’s useful in scenarios where you handle different types with a common base type in your Hub methods.
Consider the below code:
public class MyHub : Hub
{
public void Method(JsonPerson person)
{
if (person is JsonPersonExtended)
{
}
else if (person is JsonPersonExtended2)
{
}
else
{
}
}
}
[JsonPolymorphic]
[JsonDerivedType(typeof(JsonPersonExtended), nameof(JsonPersonExtended))]
[JsonDerivedType(typeof(JsonPersonExtended2), nameof(JsonPersonExtended2))]
private class JsonPerson
{
public string Name { get; set; }
public Person Child { get; set; }
public Person Parent { get; set; }
}
private class JsonPersonExtended : JsonPerson
{
public int Age { get; set; }
}
private class JsonPersonExtended2 : JsonPerson
{
public string Location { get; set; }
}
The polymorphic support is demonstrated in the Method function in the MyHub class above, which accepts a parameter of type JsonPerson (the base class) but has different behavior depending on whether the actual object is of type JsonPersonExtended or JsonPersonExtended2 (the derived classes).
This kind of polymorphic behavior can be useful in a variety of scenarios. For example,
It allows for more flexible and extensible code.
If you need to add a new derived class in the future, you can do so without changing the method signatures in your Hub classes.
It allows you to write more general code in your Hubs that can handle different types, making your code more reusable and easier to maintain.
The base type (JsonPerson) needs to be annotated to allow polymorphism. The [JsonPolymorphic] attribute indicates that the class can be used in a polymorphic scenario, and the [JsonDerivedType] attributes specify the possible derived types. This is necessary to ensure that the correct type of information is preserved when the objects are serialized and deserialized in the communication between the client and the server.
Without these annotations, the deserialization process wouldn’t know which derived class to instantiate and would create an instance of the base class. This would result in loss of information and incorrect behavior.
4. Customize OIDC and OAuth Parameter in Minimal APIs
OpenID Connect (OIDC) and OAuth are protocols used for authentication and authorization in web applications. They allow users to verify their identity and grant permissions to applications without sharing their credentials.
In the context of these protocols, parameters are used to provide additional information during the authentication and authorization process. These parameters can control various aspects of the process, such as the type of response required, the scope of the permissions, the user’s preferred authentication method, and more.
Customization of these parameters is crucial for several reasons:
Flexibility: Every application has unique requirements. Customizing parameters allows developers to tailor the authentication and authorization process to meet these specific needs.
Security: Certain parameters can enhance the security of the process. For example, the prompt parameter can be set to login to force the user to re-authenticate, ensuring that the user is indeed who they claim to be.
User Experience: Parameters like scope can be customized to request only the necessary permissions, respecting user privacy and improving their experience.
In earlier versions of .NET, customizing these parameters required overriding methods or using callbacks, which could be cumbersome. However, recent updates have introduced options like AdditionalAuthorizationParameters in the OAuth and OIDC handlers, simplifying the customization process. This allows developers to easily add or modify parameters, resulting in more readable and maintainable code.
Here’s an example of how you can customize parameters in .NET:
builder.Services.AddAuthentication().AddOpenIdConnect(options =>
{
options.AdditionalAuthorizationParameters.Add("prompt", "login");
options.AdditionalAuthorizationParameters.Add("audience", "https://api.example.com");
});
In this example, the prompt and audience parameters are being customized. The prompt parameter is set to login, forcing the user to authenticate again. The audience parameter is set to the URL of the API that the application is requesting access to.
The ability to customize OIDC and OAuth parameters is a powerful feature that allows developers to create secure, flexible, and user-friendly authentication and authorization processes. It’s an essential part of modern web application development.
5. Configure HTTP.sys extended authentication flags
Configuring HTTP.sys extended authentication flags is important for optimizing the performance and security of your ASP.NET Core applications that run on Windows and use HTTP.sys. Here’s why:
Performance Optimization: The HTTP_AUTH_EX_FLAG_ENABLE_KERBEROS_CREDENTIAL_CACHING flag (mapped to EnableKerberosCredentialCaching in ASP.NET Core) allows HTTP.sys to cache Kerberos credentials between requests. This can significantly improve performance by reducing the number of times the system needs to negotiate and establish a security context, especially in scenarios where the same client makes multiple requests quickly.
Security Enhancement: The HTTP_AUTH_EX_FLAG_CAPTURE_CREDENTIAL flag (mapped to CaptureCredentials in ASP.NET Core) allows HTTP.sys to capture the credentials used for the request. This can be useful for scenarios where you access the credentials for custom authentication or logging purposes. Capturing credentials can provide valuable information for auditing and detect and prevent unauthorized access.
Flexibility: These flags provide more control over the authentication process, allowing it to be tailored to the specific needs of your application. You can enable or disable these flags depending on your application’s requirements.
Suppose you have an ASP.NET Core application that uses HTTP.sys and needs to authenticate users based on their Windows credentials. The application is expected to handle a high volume of requests, and performance is a critical factor.
To optimize performance, you can enable Kerberos credential caching. This means that once a user’s credentials are verified, they are stored in a cache. When the user sends subsequent requests, the system can check the cache instead of having to re-verify the credentials. This can significantly reduce the time taken to authenticate requests, especially when the same user makes multiple requests within a short time.
Here’s how you can enable Kerberos credential caching using the EnableKerberosCredentialCaching property:
webBuilder.UseHttpSys(options =>
{
options.Authentication.Schemes = AuthenticationSchemes.Negotiate;
options.Authentication.EnableKerberosCredentialCaching = true;
});
In addition to improving performance, you might also want to enhance the security of your application. For instance, you might want to log the credentials used for each request for auditing purposes.
To do this, you can enable credential capturing using the CaptureCredentials property:
webBuilder.UseHttpSys(options =>
{
options.Authentication.Schemes = AuthenticationSchemes.Negotiate;
options.Authentication.CaptureCredentials = true;
});
With these configurations, your application can handle a high volume of requests more efficiently without compromising on security. This is why configuring HTTP.sys extended authentication flags is important for optimizing the performance and security of your ASP.NET Core applications that run on Windows and use HTTP.sys.
6. Improved debugging display of dictionaries
When you’re debugging an application, it is necessary to inspect the contents of various data structures at runtime. Dictionaries, which store data as key-value pairs, are commonly used data structures in .NET applications.
In earlier versions of .NET, when you inspected a dictionary while debugging, both the key and the value were displayed together. This could sometimes make it difficult to distinguish between the keys and values, especially if they were complex objects or long strings.
Starting from .NET 6, the debugging display of dictionaries has been improved. Now the key is displayed separately in the debugger’s key column, and the value is displayed in the value column. This makes it much easier to distinguish between keys and values at a glance.
This improvement is particularly beneficial when working with ASP.NET Core, which uses dictionaries and other key-value collections in many places, including:
HTTP headers
Query strings
Forms
View data
Route data
Features
By improving the debugging display of these collections, .NET has made it easier for developers to inspect and understand their data during debugging, leading to more efficient troubleshooting and bug fixing.
Conclusion
The latest features in ASP.NET Core demonstrate its continuous evolution to meet the needs of modern web development. From improved debugging displays of dictionaries to the configuration of HTTP.sys extended authentication flags, each enhancement contributes to making ASP.NET Core a more powerful, flexible, and efficient framework for building web applications.
As developers, staying abreast of these updates allows us to leverage the full potential of the framework and build applications that are more secure, performant, and user-friendly.
So, let’s continue exploring, learning, and creating with ASP.NET Core!
Comments