Showing posts with label DotNet/dotnetCore. Show all posts
Showing posts with label DotNet/dotnetCore. Show all posts

.NET 7 Features | .NET 7 is Available Now | What 's new in .NET 7?

 In this article, we will discuss .NET 7 features. 



So recently Microsoft release .NET 7 which contains a performance improvement and new features in the below application.

  1. C# 11
  2. F# 7
  3. .NET MAUI
  4. ASP.NET Core/Blazor
  5. Web APIs, 
  6. WinForms
  7. WPF and more. 

With .NET 7, now we can containerize our .NET 7 application and set up CI/CD workflows in GitHub.

We can Download .NET 7 from here.

C# 11 Updates

NET 7 is released with the new feature of C# 11. if you want to see the full list of changes then see the list of new features in C# 11.

Generic Math Support

Generic math support is unlocked by the other new feature of C# 11, static abstract and virtual members, which might otherwise seem like a pretty obscure object-oriented programming (OOP) change. 

File-Scoped Types

You can use the file access modifier to create a type whose visibility is scoped to just the source file in which it is declared. This can help you avoid naming collisions.

Auto-Default Structs

All fields and auto-properties of a struct type are now automatically initialized to their default value if they are not set by the constructor.

UTF-8 String Literals

By default, C# strings are hardcoded to UTF-16, whereas the prevailing string encoding on the internet is UTF-8. To minimize the hassle and performance overhead of converting, you can now simply append a u8 suffix to your string literals to get them in UTF-8 right away:

You can specify the u8 suffix on a string literal to specify UTF-8 character encoding.

byte[] u8Span = "ABC"u8;
u8Span.ToArray().Should().BeEquivalentTo(new[] { 65, 66, 67 });

var u8 = "This is a UTF-8 string!"u8;

Required Members

The required modifier indicates that a field or property must be initialized either by the constructor method or by an object initializer statement used when calling the constructor.

public class Person
{
    public required string FirstName { get; init; }
    public string? MiddleName { get; init; }
    public required string LastName { get; init; }
}

It is now an error to create a Person without initializing both the required properties:

var person = new Person { FirstName = "Ada" }; // Error: no LastName!

Raw String Literals

Raw string literals are a new format for string literals that can contain arbitrary text, including whitespace, new lines, embedded quotes, and other special characters without requiring escape sequences. 

A raw string literal starts with three or more double quotes and ends with a matching number of double quotes. This can be great for JSON-formatted string data, as in the following example

A raw string literal is delimited by at least three double quotes:

var raw1 = """This\is\all "content"!""";
Console.WriteLine(raw1);

This prints:

This\is\all "content"!

Generic Attributes

You can now create a generic class that inherits from System. Attribute. This feature provides a more convenient syntax for attributes that require a Type parameter.

// Before C# 11:
public class TypeAttribute : Attribute
{
   public TypeAttribute(Type t) => ParamType = t;
   public Type ParamType { get; }
}

[TypeAttribute(typeof(string))]
public string Method() => default;
Using this new feature, you can create a generic attribute instead:


// C# 11 feature:
public class GenericAttribute<T> : Attribute { }
Then, specify the type parameter to use the attribute:

[GenericAttribute<string>()]
public string Method() => default;

Newlines in String Interpolation Expressions

The text inside the { and } characters for an interpolated string can now include new-line characters, allowing you to write more complex, multi-line C# expressions in your interpolated strings.

List Patterns

The very powerful pattern-matching feature in C# now includes array/list patterns.

C# 11 adds list patterns to the story. With list patterns, you can apply patterns recursively to the individual elements of list-like input – or to a range of them. Let’s jump right in with the generic algorithm from above, rewritten as a recursive method using list patterns:

T AddAll<T>(params T[] elements) where T : IMonoid<T> =>
    elements switch
{
    [] => T.Zero,
    [var first, ..var rest] => first + AddAll<T>(rest),
};
public static int CheckSwitch(int[] values)
    => values switch
    {
        [1, 2, .., 10] => 1,
        [1, 2] => 2,
        [1, _] => 3,
        [1, ..] => 4,
        [..] => 50
    };

WriteLine(CheckSwitch(new[] { 1, 2, 10 }));          // prints 1
WriteLine(CheckSwitch(new[] { 1, 2, 7, 3, 3, 10 })); // prints 1
WriteLine(CheckSwitch(new[] { 1, 2 }));              // prints 2
WriteLine(CheckSwitch(new[] { 1, 3 }));              // prints 3
WriteLine(CheckSwitch(new[] { 1, 3, 5 }));           // prints 4
WriteLine(CheckSwitch(new[] { 2, 5, 6, 7 }));        // prints 50

.NET MAUI Updates

In .NET 7, MAUI now has several new features, including a new Map control, better support for dual-screen devices, improvements to the UI responsiveness, faster startup, and better overall app size. Microsoft has also released a migration assistant for upgrading your Xamarin projects to .NET MAUI.

ASP.NET 7 Updates

With the web and web APIs still being at the center of so many modern applications, server-side ASP.NET is as important as ever. The ASP.NET team continues to make major investments into ASP.NET Core in .NET 7, including the handful of our favorite new features below:

Rate-Limiting Middleware

If you want to limit the traffic you get to a web application or API, you have a new option with rate-limiting middleware that controls the load on your application by queueing up traffic when it exceeds certain limits. This prevents other parts of your application from becoming a bottleneck.

MVC and Razor Pages

Microsoft hasn’t forgotten about server-side web applications, either. MVC and Razor pages got some improvements, like nullable models and a customized cookie consent value. You can read more about these changes on the Microsoft Learn site.

API Controllers

API controllers can now use the new decompression middleware to allow them to handle requests with compressed content. Controller classes also get better dependency injection support without the need to use the [FromServices] attribute.

Minimal APIs

We’re excited about Minimal APIs here at Trailhead. They are the new, low-code way to define web API endpoints in ASP.NET. 

Minimal APIs get some big improvements in .NET 7, including the addition of filters. This allows you to run code before or after your route handlers, or to inspect and modify your requests or responses. Other changes make unit tests easier to write for minimal APIs, add better support for the OpenAPI standard (formerly known as Swagger), and make streaming and file uploads easier.

Finally, minimal APIs built in .NET 7 will have new ways of defining routes in groups that share the same base path or other common configuration settings.

gRPC

A new transcoder middleware allows you to write gRPC services that also operate as RESTful JSON APIs. This allows you to use the latest and greatest web service technologies while still providing backward compatibility for clients who haven’t been upgraded to use gRPC.

Performance

Output caching is a new middleware in .NET 7 which stores responses from a web app and serves them from a cache. 

HTTP/3 is also now fully supported, and Kestrel can handle HTTP/2 traffic much faster than it used to in .NET 6.  There is even new support for running SignalR WebSockets over HTTP/2, something that we’ve sorely missed in previous versions.

You can read more about the many great performance improvements for ASP.NET Core in .NET 7 here.

Other

There is new and improved console output for the Dotnet watch now. The developer exception page in ASP.NET has a dark mode in .NET 7. If you prefer to use Program.Main instead of top-level statements, there’s a Dotnet new command-line switch for that. Also, Dotnet new includes new React and Angular starter templates, and the Dotnet command-line interface includes new tooling for JWTs.

Cloud Native and Containers

Our .NET applications have been able to run in containers for a long time now, but with .NET 7, Microsoft has added support for creating containerized applications as part of a build-publish process, with no need for an explicit Docker build phase.

With so many cool new features, we suspect many of you will be as eager as we are to incorporate .NET 7 into your projects. 

ARM64 Support

These days ARM processors are getting more and more common because of their high performance and low power consumption. With this release, .NET now fully supports targeting the ARM architecture.

Conclusion

If you are planning to work with  .NET 7, then we would like to tell Microsoft follows the tick-tock pattern with all .NET versions. 

All even-numbered versions come under long-term support (LTS) and all odd-numbered versions come under standard-term support (STS), which is almost 18 months. 

Because .NET 7 is the odd version number, it is an STS release. You should only upgrade if you also plan to upgrade your code again in about a year when .NET 8 comes.




-----------------------------------------------------

API Key Authentication in ASP.NET Core Web API

 In this tutorial, we will learn how to use API Key authentication to secure ASP.NET Core Web API in 2 different ways: 

  • Custom Attribute 
  • Custom Middleware.

Keep in mind that using API Key Authentication should be limited to the service clients or well-known clients, in other words, it is not recommended that you use the API Key Authentication to actually authenticate your users, it is mainly used to identify and authorize a project or service that is connecting to your APIs. So it will keep a secure link between your APIs and the client of your APIs 

Lets Open Visual Studio 2022 and create a new project and choose ASP.NET Core Web Application template.





Now give a project name like ‘SecuringWebApiUsingApiKey’ and then press Next:



Now select the .NET Framework 6.0 and click next

After clicking on Next,you will see below the Project structure



Now run the application, and you will see the below output in the browser



There are many ways to implement the API Key Authentication, in this tutorial we will see  2 ways.

1. API Key Authentication Using Custom Attributes

Now we will create a new custom attribute which will be inherited from ASP.NET Core Attributes and it will create the IAsyncActionResult interface

We will verify that the ApiKey header exists, has a value and its value is actually the correct API Key, unless otherwise, we will return a 401 Unauthorized response to the client indicating that the request is not authorized to access the endpoint.

So now let's add an Attribute:

Right-click on your project and choose to add New Folder

Give it a name, like CustomeAttributes

then right-click on the Attributes folder, and choose to add then New item …

Let’s name the Attribute as ApiKeyAuthAttribute.

Now you should have a new class under the Attributes folder as below:



We will be using this attribute to decorate the controller so that any request that is routed to the attributed controller will be redirected to ApiKeyAuthAttribute

Your custom attribute will be inherited from the base abstract class Attribute of Global System. Attribute, which will transform your class into a custom attribute,

And also you will be implementing the IAsyncActionFilter Interface so that your custom attribute will be able to intercept the call request, process it, and then route the request back to the controller.

Now let’s see what we will do in this custom attribute:

using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;

namespace APIKeyAuthentication.CustomeAttributes
{
    [AttributeUsage(validOn: AttributeTargets.Class)]
    public class ApiKeyAuthAttribute : Attribute, IAsyncActionFilter
    {
        private const string apiKeyName = "ApiKey";
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            if (!context.HttpContext.Request.Headers.TryGetValue(apiKeyName, out var extractedApiKey))
            {
                context.Result = new ContentResult()
                {
                    StatusCode = 401,
                    Content = "Api Key is not Given"
                };
                return;
            }
            var appSettings = context.HttpContext.RequestServices.GetRequiredService<IConfiguration>();
            var key = appSettings.GetValue<string>(apiKeyName);
            if (!key.Equals(extractedApiKey))
            {
                context.Result = new ContentResult()
                {
                    StatusCode = 401,
                    Content = "Api Key is not valid"
                };
                return;
            }
            await next();
        }
    }
}

so let me explain what we are doing:

[AttributeUsage(validOn: AttributeTargets.Class)]

this decoration is also an Attribute that indicates and specifies where the ApiKeyAuthAttribute will be used, in our case we have specified that ApiKeyAuthAttribute will only be used on classes, like Controllers.

The AttributeTargets is an enum that applies flags, so you can use the pipe | operator (bitwise or) to specify more usages for your custom attribute, so the below would indicate the ApiKeyAuthAttribute can be used on both classes and/or methods (Controller and/or action method)

[AttributeUsage(validOn: AttributeTargets.Class | AttributeTargets.Method)]

Ok, so now allow me to explain the first logical section of the code:

if (!context.HttpContext.Request.Headers.TryGetValue(apiKeyName, out var extractedApiKey))
{ context.Result = new ContentResult() { StatusCode = 401, Content = "Api Key not Given" }; return; }
In the above code, we are first checking the request headers collection object if it has a key with the name ApiKey. Of course, you can use whatever header name you like.

Now if the header doesn’t include the ApiKey as a key, then we will return a 401 Unauthorized response code with a message indicating that the API Key was not provided.

You can leave the Content field empty or just simply return UnauthorizedResult instead of ContentResult without having to specify the StatusCode and the Content and that will just return 401 without any message.

If the ApiKey header was sent, we will then move to the next step which is validating that the value of the ApiKey header matches the ApiKey defined in our API project.

Now, let’s go and create an API Key. For the sake of this tutorial, we will be adding the API Key inside the appsettings.json file, which is the settings file that resides in your ASP.NET Core Web API Project.

so let’s open it and add the ApiKey setting, as the below:



Notes:

It is always important to choose an API Key that is strong enough (a combination of a random and unique long number of alphanumeric characters), just to make it easier to guess and random.

On another note, never share the same API Key with more than 1 client, the intent of the API Key is to authenticate the client or the project, so you need to keep it unique per client.

Now let’s go back to our example and explain the rest of the method:

There are several ways to read the appsettings.json file in ASP.NET Core Web API Project, but you can rely on the dependency injection and configuration extensions libraries of Microsoft to get load the settings file and read its values:

var appSettings = context.HttpContext.RequestServices.GetRequiredService<IConfiguration>();
var apiKey = appSettings.GetValue<string>(apiKeyName);

Now we have obtained our API Key value that is defined within the appsettings.json file, we will match it versus the extracted API Key value from the request headers collection. If both match, then we are good to route the request to the controller to run its intended HTTP action (get, post…etc)

Otherwise, we will fail the request with a 401 Unauthorized response and a message indicating that the client is unauthorized.

if (!apiKey.Equals(extractedApiKey))
            {
                context.Result = new ContentResult()
                {
                    StatusCode = 401,
                    Content = "Unauthorized client"
                };
                return;
                }

The Decoration

Now, the final part we want here is that we need to decorate our Controller with the ApiKey Attribute so that we can authenticate the client that is calling our endpoint

So open WeatherForecastController and add [ApiKey] above the WeatherForecastController class:

[ApiKeyAuth]
public class WeatherForecastController : ControllerBase

Make sure to include the new namespace at the top of the controller class:

using APIKeyAuthentication.CustomeAttributes;


Now let’s run our application and notice the message on the browser:



Testing on Postman

To have better visibility of what’s happening and control our testing parameters we will be using Postman.

Keep the localhost running on your browser, and open Postman.

Now, let’s try to run the same URL without sending anything in the headers, notice the status is: 401 Unauthorized and the response body is showing the message “API Key was not provided”

401 Unauthorized. API Key was not provided.



Now let’s try to send the correct header name but with the wrong value, you will get the same Status as 401,

401 Unauthorized. Unauthorized Client.



Now let’s make our client pass the validation by sending the correct API Key in the header:

200 OK



And now we have a response code of 200 OK and the response body is the actual data returned by the default GET method of /weatherforecast endpoint.

2. API Key Authentication Using a Custom Middleware

With a custom ASP.NET Core Middleware, you are able to intercept and process the request object in a single place.

You can intercept each and every request that comes to your published web APIs and tap into the request headers collection and search for the API key header and validate its value.

So we will be doing almost exactly the same logic which we did in our custom attribute but this time within a middleware.

Let’s begin by creating a new folder with the name ‘CustomeMiddleware’ and then followed by a class file with the name ApiKeyAuthMiddleware:



What defines a middleware is its constructor that takes an instance of RequestDelegate Class, this instance is actually the pipeline passed between the ASP.NET Core Middleware collection. so this custom middleware will also receive this instance of pipeline and do some operations on it.

The next important thing is the InvokeAsync method that you need to define in this middleware so that it will contain the main process and in our case, the main process will be to search and validate the ApiKey header name and value within the HTTP context request headers collection, so this need to be passed in the method argument.

namespace APIKeyAuthentication.CustomeMiddleware
{
    public class ApiKeyAuthMiddleware
    {
        private readonly RequestDelegate _next;
        private const string apiKeyName = "ApiKey";
        public ApiKeyAuthMiddleware(RequestDelegate next)
        {
            _next = next;
        }
        public async Task InvokeAsync(HttpContext context)
        {
            if (!context.Request.Headers.TryGetValue(apiKeyName, out var extractedApiKey))
            {
                context.Response.StatusCode = 401;
                await context.Response.WriteAsync("Api Key not given with Middleware ");
                return;
            }
            var appSettings = context.RequestServices.GetRequiredService<IConfiguration>();
            var key = appSettings.GetValue<string>(apiKeyName);
            if (!key.Equals(extractedApiKey))
            {
                context.Response.StatusCode = 401;
                await context.Response.WriteAsync("Api Key is not valid /Unauthorized with ApiKeyAuthMiddleware");
                return;
            }
            await _next(context);
        }
    }
}


It is somehow similar to what we have done in the custom attribute, but the main difference that you will notice here is that we cannot directly set the Response object of the context but we have to assign the status code and message separately.

context.Response.StatusCode = 401;
await context.Response.WriteAsync("Api Key not given with Middleware");

Now the middleware has to be injected or included in our pipeline, we will do this in the Program.cs class

Add the following line:

app.UseMiddleware<ApiKeyAuthMiddleware>();

And below is how your program.cs file should look like this while injecting the ApiKeyAuthMiddleware into the app pipeline:



This way you will be applying this custom API Key Middleware over every single controller in your project, not just specific controller or method like the custom attributes.

Middleware is also very useful in other situations such as where you want to apply logging and general exception handling over your all APIs. There are so many use cases for using the ASP.NET Core Middleware.

So now, just before you run the application again, just make sure to remove the [ApiKey] attribute from your WeatherForecastController so that we can test the new middleware

Now let’s run the application and see.



401 Unauthorized. API Key was not provided. (Using ApiKeyAuthMiddleware)



401 Unauthorized. Unauthorized Client. Using ApiKeyAuthMiddleware



200 OK



This way you will be applying the HTTP message handler over every single endpoint not just specific like the custom attributes, where you can decorate the endpoints of your choice with the custom attribute to check for the API key.

Summary

We have seen how API Key Authentication in  ASP.NET Core Web API with 2 ways of implementing the API Key Authentication: Custom Attributes and Custom Middleware.




---------------------------------