1

.NET 8.0 Preview 5, 6, and 7 - Part 2

 9 months ago
source link: https://devm.io/dotnet/dot-net-preview-part-two
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

.NET 8.0 Preview 5, 6, and 7

In .NET 8 previews 5, 6, and 7, Microsoft is gradually realizing the Blazor United promises. There are also new language features for C# 12.0 and improvements to the AOT compiler, ASP.NET Core, .NET MAUI, and even a new control for WPF.

The final version of.NET 8.0 releases November 14, 2023 and had a release candidate prior to that. Microsoft usually associates a go-live license with release candidate versions, meaning productive use of .NET 8.0 is permitted from then on. However, that doesn’t mean there aren’t any changes between release candidate and the final release.

Global cascading Blazor values

Previously, cascading values could only be defined in Razow components. But in .NET 8.0, they can now be registered by developers in a Blazor application’s code start in Program.cs to make these values available as a state component for all components. To do this, and object can be registered without an explicit name:

builder.Services.AddCascadingValue(sp => new Author { Name = "Dr. Holger Schwichtenberg1", Url = "www.dotnet-doktor.de" });

Or by name:

builder.Services.AddCascadingValue("author2", sp => new Author { Name = "Dr. Holger Schwichtenberg", Url = "www.dotnet-doktor.de" });

Or by CascadingValueSource:

builder.Services.AddCascadingValue(sp =>

{

var a = new Autor { Name = "Holger Schwichtenberg", Url = "www.dotnet-doktor.de" };

var source = new CascadingValueSource<Autor>("autor3",a, isFixed: false);

return source;

});

Each Razor component in the Blazor application can consume and modify this object (Listing 1).

Listing 1

@code

{

[CascadingParameter]

Author author1 { get; set; }

[CascadingParameter(Name = "author2")]

Author author { get; set; }

[CascadingParameter(Name = "author3")]

Author author { get; set; }

[ParameterAttribute]

public int id { get; set; }

protected override void OnInitialized()

{

author3.Name = "Dr. " + author3.Name;

}

}

Antiforgery token for protection against cross-site request forgery

To protect against attacks based on the principle of cross-site request forgery (CSRF/XSRF), Microsoft provides a new middleware in ASP.NET Core 8.0 from Preview 7 onwards. Developers can integrate this into the start code of an ASP.NET Core application using builder.Services.AddAntiforgery();. Initially, this call only activates the IAntiforgeryValidationFeature in the processing pipeline. A web framework based on ASP.NET Core (e.g. Blazor, WebAPI, MVC, Razor Pages) must then take an antiforgery token into account in the program code. This blog entry shows implementation examples for ASP.NET Core Minimal APIsand Blazor (when using ). However, it does not discuss what the implementation status is for other ASP.NET Core-based web frameworks like MVC and Razor Pages.

WebCIL is now the standard for Blazor WebAssembly

The WebCIL format for Blazor WebAssembly has been available since .NET 8.0 Preview 4 and has been active as the standard since Preview 7. The implementation of WebCIL with WebAssembly modules aims to prevent Blazor WebAssembly from being blocked by firewalls and anti-virus software. Microsoft has adapted the format so that standard WebAssembly modules are generated with the file name extension .wasm (in Preview 4, it was still .webcil).

Developers have the option of deactivating WebCIL by using the false switch in the project file. However, in the blog entry, Microsoft doesn’t give any explicit information about scenarios where this could be useful. Previously, the Blazor WebAssembly files were provided with the .dll extension by default.

Identity Server is out

As announced at the Build conference in May 2023, Microsoft removed the Duende Identity Server from its project templates for React and Angular projects with an ASP.NET Core backend. The .NET development team did this because the Identity Server was available in versions 1 to 4 as an open source software and was a project from the non-profit .NET Foundation. It has now become a commercial project. Only open source projects are exempt from license fees. Microsoft decided to base these project templates on the identity system integrated into ASP.NET Core. For developers who wish to continue using the Identity Server, Microsoft offers the Duende documentation.

Additional WebAPIs for ASP.NET Core Identity

In .NET 8.0 Preview 4, Microsoft introduced WebAPI endpoints for ASP.NET Core Identity, the integrated user management system for ASP.NET Core. This addition was made alongside the existing web interface, which is based on server-side rendering. This integrates ASP.NET Core Identity more effectively into single-page web applications (using JavaScript or Blazor). Previously, the available WebAPI endpoints were limited to user registration (/register) and user login (/login).

Preview version 7 added additional endpoints. These include confirming user accounts via email (/confirmEmail and / resendConfirmationEmail), resetting passwords (/resetPassword), updating tokens (/refresh), support for 2-factor authentication (/account/2fa), and reading and updating profile data (/account/ info).

Activating these WebAPI endpoints for ASP. NET Core Identity is done in Program.cs by calling the AddApiEndpoints() function after AddIdentityCore(). See Listing 2.

Listing 2: Start code for an ASP.NET Core application that provides user management with ASP.NET Core Identity via WebAPI (Source)

using System.Security.Claims;

using Microsoft.AspNetCore.Identity;

using Microsoft.AspNetCore.Identity.EntityFrameworkCore;

using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthentication().AddBearerToken(IdentityConstants.BearerScheme);

builder.Services.AddAuthorizationBuilder();

builder.Services.AddDbContext<AppDbContext>(options => options.UseInMemoryDatabase("AppDb"));

builder.Services.AddIdentityCore<MyUser>()

.AddEntityFrameworkStores<AppDbContext>()

.AddApiEndpoints();

// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle

builder.Services.AddEndpointsApiExplorer();

builder.Services.AddSwaggerGen();

var app = builder.Build();

// Adds /register, /login and /refresh endpoints

app.MapIdentityApi<MyUser>();

app.MapGet("/", (ClaimsPrincipal user) => $"Hello {user.Identity!.Name}").RequireAuthorization();

if (app.Environment.IsDevelopment())

{

app.UseSwagger();

app.UseSwaggerUI();

}

app.Run();

class MyUser : IdentityUser { }

class AppDbContext : IdentityDbContext<MyUser>

{

public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }

Fault tolerance with ASP.NET Core SignalR

The ASP.NET Core SignalR notification service can now automatically re-establish its connection seamlessly after brief disconnections (Seamless Reconnect). However, since .NET 8.0 Preview 5, it only works with .NET clients for now. A .NET client must establish the connection with the addition of UseAcks = true:

var hubConnection = new HubConnectionBuilder()

.WithUrl("https://ServerName/Hub">",

options =>

{

options.UseAcks = true;

})

.Build();

There isn’t any configuration of this fault tolerance yet, but it is in progress. Blazor Server will also benefit from the new fault tolerance since it uses ASP.NET Core SignalR for transmitting of page changes.

New features in C# 12.0

There are four new C# 12.0 language features in previews 5 to 7, the main innovation being collection literals. With this new syntax form, the previously heterogeneous initialization forms of object sets can be strongly standardized in the style of JavaScript. This is done with values in square brackets, separated by commas (Table 1).

Previous initialization Now possible
int[] a = new int[3] { 1, 2, 3 }; int[] a = [1,2,3];
Span b = stackalloc[] { 1, 2, 3 }; Span b = [1,2,3];
ImmutableArray c = ImmutableArray.Create(1, 2, 3); ImmutableArray c = [1,2,3];
List d = new() { 1, 2, 3 }; List d = [1,2,3];
IEnumerable e = new List() { 1, 2, 3 }; IEnumerable e = [1,2,3];

Listing 3: Extensions for nameof() in C# 12.0

/// <summary>

/// nameof-extension in C# 12.0, see also:

/// https://github.com/dotnet/csharplang/issues/4037

/// </summary>

[Description($“{nameof(StringLength)} returns the property {nameof(Name.Length)}“)]

public struct Person

{

public string Name;

public static string MemberName1() => nameof(Name); // already possible

public static string MemberName2() => nameof(Name.Length); // so far: error CS0120: An object reference is required for the non-static field, method, or property ‘Name.Length’

public void PrintMemberInfo()

{

Console.WriteLine($“Die Struktur {nameof(Person)} has a member {nameof(Name)}, which is a property of {nameof(Name.Length)} has!“); // The structure Person has a member Name that has a property Length!

}

[Description($“{nameof(StringLength)} returns the property {nameof(Name.Length)}“)]

public int StringLength(string s)

{

return s.Length;

}

}

Other new features in C# 12.0 include:

  • The nameof operator now also works with member names, including initializers, for static members and in attributes (Listing 3).
  • An interceptor allows a method call to be intercepted and redirected. Microsoft intends to primarily use this and make more code compatible with the ahead-of-timer compiler.
  • Inline arrays are now available for optimization.

Improvements in the native AOT compiler

The ahead-of-time compilation for ASP.NET Core Minimal WebAPIs has been available since .NET 8.0 Preview 3. It can now also handle complex objects that are annotated with [AsParameters].

Since .NET 8.0 Preview 6, Microsoft has made it possible to compile .NET applications for iOS, Mac Catalyst, and tvOS with the new .NET Native AOT compiler. This option is available for apps that are restricted to these platforms (".NET for iOS") and the .NET Multi-Platform App UI (.NET MAUI). As a result, the applications no longer run on Mono and the app packages for ".NET for iOS" are noticeably more compact. The app packages for .NET MAUI have also gotten larger (Fig. 1). In a blog entry, Microsoft confirmed they recognize this problem and are actively working on finding a solution that will lead to a size advantage of roughly 30 percent.

Figure 1

Fig. 1: Reduced app packages through Native AOT (Image source: Microsoft)

Improvements for System.Text.Json

In .NET 8.0 Preview 6 and 7 included improvements for the JSON serializer/deserializer in the NuGet package System.Text.Json.

System.Text.Json can now serialize newer number types such as Half, Int128 and UInt128 as well as the memory types Memory and ReadOnlyMemory. With the latter, Base64-encoded character strings are created when Memory and ReadOnlyMemory are involved. Other data types are serialized as JSON arrays.

Example 1:

JsonSerializer.Serialize<ReadOnlyMemory<byte>>(new byte[] { 42, 43, 44 }); becomes "Kiss"

Example 2:

JsonSerializer.Serialize<Memory<Int128>>(new Int128[] { 42, 43, 44 }); becomes [42,43,44]

Example 3:

JsonSerializer.Serialize<Memory<string>>(new string[] { "42", "43", "44" }); becomes ["42","43","44"]

The annotations [JsonInclude] and [JsonConstructor] also allow developers to enforce the serialization of non-public class members. For each non-public member annotated with [JsonInclude], a parameter must be in the constructor annotated with [JsonConstructor] in order to set the value during deserialization. Listing 4 shows an example.

Listing 4: Serializing and deserializing with [JsonInclude] und [JsonConstructor]

public class Person

{

[JsonConstructor] // ohne dies: ‘Deserialization of types without a parameterless constructor, a singular parameterized constructor, or a parameterized constructor annotated with ‘JsonConstructorAttribute’ is not supported.

internal Person(int id, string name, string website)

{

ID = id;

Name = name;

Website = website;

}

[JsonInclude] // without this: ‘Each parameter in the deserialization constructor on type ‘FCL_JSON+Person’ must bind to an object property or field on deserialization. Each parameter name must match with a property or field on the object. Fields are only considered when ‘JsonSerializerOptions.IncludeFields’ is enabled. The match can be case-insensitive.’

internal int ID { get; }

public string Name { get; set; }

[JsonInclude] // without this: ‘Each parameter in the deserialization constructor on type ‘FCL_JSON+Person’ must bind to an object property or field on deserialization. Each parameter name must match with a property or field on the object. Fields are only considered when ‘JsonSerializerOptions.IncludeFields’ is enabled. The match can be case-insensitive.’

private string Website { get; set; }

public override string ToString()

{

return $"{this.ID}: {this.Name} ({this.Website})";

}

}

...

// Serializing

var p1 = new Person(42, „Dr. Holger Schwichtenberg“, „www.dotnet-doktor.de“);

string json4 = JsonSerializer.Serialize(p1); // {"X":42}

Console.WriteLine(json4);

// Deserializing

var p2 = JsonSerializer.Deserialize<Person>(json4);

Console.WriteLine(p2);

The JsonNode class has been given new methods like DeepClone() and DeepEquals(). Furthermore, JsonArray now offers IEnumerable, allowing enumeration with foreach and Language Integrated Query (LINQ):

JsonArray jsonArray = new JsonArray(40, 42, 43, 42);

IEnumerable<int> values = jsonArray.GetValues<int>().Where(i => i == 42);

foreach (var v in values)

{

Console.WriteLine(v);

}

One of the new System.Text.Json features in version 8.0 is that the annotation [JsonSourceGenerationOptions], which can be applied to classes to be serialized, now gives all the options that the JsonSerializerOptions class also gives for imperative programming with the System.Text.Json. JsonSerializer class. There is a new annotation [JsonConverter] for System.Text.Json along with Native AOT:

[JsonConverter(typeof(JsonStringEnumConverter<MyEnum>))]

public enum MyEnum { Value1, Value2, Value3 }

Source Generator for COM

In .NET 7.0 Preview 6, Microsoft presented the Source Generator for native API calls with the [LibraryImport] annotation for all operating system platforms. In .NET 8.0 Preview 6, a similar option for using the Component Object Model (COM) was introduced. This is only available on Windows. To use the COM interface, the corresponding wrapper must have the annotation [GeneratedComInterface]. Classes that implement these interfaces are annotated with [GeneratedComClass]. Besides the [LibraryImport} annotation introduced in .NET 7.0, developers can now also use COM interfaces as parameter and return types. These allow the C# compiler to generate the COM access code - which is usually generated at runtime - at development time. Generated code can be found in the project under /Dependencies/Analyzers/Microsoft.Interop.ComInterfaceGenerator.

For existing interfaces with [ComImport] annotations, Visual Studio suggests converting them to [GeneratedComInterface]. Similarly, for classes that implement these interfaces, Visual Studio suggests annotating them with [GeneratedComClass].

Just as always, Microsoft includes errors in the announcement blog entry. The keyword partial is missing in all of the examples discussed in connection with COM. Microsoft writes:

[GeneratedComInterface]

[Guid("5401c312-ab23-4dd3-aa40-3cb4b3a4683e")]

interface IComInterface

{

void DoWork();

void RegisterCallbacks(ICallbacks callbacks);

}

However, this code leads to a compiler error in Visual Studio 2022 (both in 17.7 Preview 3.0 released with Preview 6 and in 17.8 Preview 1): "The interface 'IComInterface' or one of its containing types is missing the 'partial' keyword. Code will not be generated for 'IComInterface'." This is correct:

[GeneratedComInterface]

[Guid("5401c312-ab23-4dd3-aa40-3cb4b3a4683e")]

partial interface IComInterface

{

void DoWork();

void RegisterCallbacks(ICallbacks callbacks);

}

Microsoft documented some of the source generator for COM’s limitations. This includes the fact that the generator doesn’t work for interfaces based on IDispatch and IInspectable. Neither COM properties nor COM events are supported. It’s important to note that developers cannot activate a COM class with the keyword new. This is only possible by calling CoCreate-Instance(). These restrictions will remain and any improvements will only be in later major versions.

New OpenFolderDialog control for WPF

For many years, there were no new controls for the Windows Presentation Foundation (WPF). In .NET 8.0 Preview 7, Microsoft added a new dialog for selecting folders in the file system (Listing 5). The standard Windows operating system dialog opens. But the Microsoft.Win32.OpenFolderDialog class wasn’t implemented by Microsoft itself, but by community member Jan Kučera.

Listing 5: Usage example for the new WPF control OpenFolderDialog

OpenFolderDialog openFolderDialog = new OpenFolderDialog()

{

Title = "Select folder to open ...",

InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),

};

string folderName = "";

if (openFolderDialog.ShowDialog() == true)

{

folderName = openFolderDialog.FolderName;

}

Keyboard shortcuts for .NET MAUI menus

As announced, the .NET MAUI development team is focusing on bug fixes in .NET 8.0. Refer to the blog entries for Preview 5, Preview 6 and Preview 7.

Keyboard shortcuts are a major new feature in these three previews. Developers can now assign them to a menu item with SetAccelerator():

<MenuFlyoutItem x:Name="AddProductMenu"

Text="Add Product"

Command="{Binding AddProductCommand}"

/>

...

MenuItem.SetAccelerator(AddProductMenu, Accelerator.FromString("Ctrl+A"));

The main blog entry for .NET 8.0 Preview 7 mentions an improvement for internationalized mobile applications on Apple operating systems (iOS, tvOS and MacCatalyst). The size of the country-specific data can be reduced by 34 percent with a new setting:

true

However, some APIs change their behaviour through hybrid globalization. Hybrid globalization is also possible in .NET applications running on Webassembly. The setting loads the icudt_hybrid.dat file, which should be 46 percent smaller than the previous icudt.dat.

There’s also a .NET MAUI extension for Visual Studio Code.

Silence from Entity Framework Core

The Entity Framework Core development team is quiet right now. Although there was a new version for previews 5, 6 and 7 on NuGet, there was no separate blog entry from the Entity Framework Core development team, as is usually the case for all preview versions. The GitHub issue where Entity Framework Core engineering manager Arthur Vickers used to report progress biweekly, only had an entry with a few minor improvements on June 22 and July 6.

According to a table in the aforementioned issue, the development team has already completed most of the smaller innovations in Entity Framework Core and is working on larger projects. These include:

  • Tree shaking/trimming and ahead-of-time compilation for ADO.NET and Entity Framework Core
  • A new, faster Microsoft SQL Server database driver for ADO.NET and Entity Framework Core with the code name "Woodstar"
  • Mapping of value objects for Domain-Driven Design
  • Improved tools for database-first development (reverse engineering) in Visual Studio

Conclusion

.NET 8.0 offers exciting new features in previews 6, 7 and 8. It’s clear that Microsoft is actually implementing Blazor United. The Entity Framework Core development team still has a lot to deliver.

Miscellaneous innovations

Besides the new features we discussed in the main text, let’s discuss some further improvements in .NET 8.0 Previews 5, 6 and 7.

Figure 2

Fig. 2: Improved debugger view in ASP.NET Core projects (Image source: Microsoft)

  • In the .NET 8.0 SDK, when publishing a .NET 8.0 application with dotnet publish, specifying a runtime identifier (with --runtime or -r for short) no longer automatically results in the creation of a self-contained app (SCA). Previously, if you didn’t want this, you had to specify --no-self-contained. This is one of the many breaking changes in .NET 8.0.
  • .NET 8.0 Preview 5 included an improvement to the Metrics API. You can now use dependency injection to obtain an object with the IMeterFactory interface if you’ve previously called services.AddMetrics().
  • The System.IO.Compression.ZipFile class, which has been available since the classic .NET Framework 4.5 and in modern .NET since version .NET Core 1.0, has two new static methods CreateFromDirectory() and ExtractToDirectory(). These allow a ZIP archive to be created directly from a file system folder or unpacked into a target folder.
  • In ASP.NET Core, there’s a new method CreateEmptyBuilder() in the WebApplication class. This creates a WebApplicationBuilder without predefined behavior. The caller must add all middleware and services themselves. In return, the application bundle is smaller.
  • Since Preview 5, ASP.NET Core WebAPI has generic annotations for cases where you previously had to pass a parameter of type System.Type: [ProducesResponseType], [Produces], [MiddlewareFilter], [ModelBinder], [ModelMetadataType], [ServiceFilter] and [TypeFilter].
  • The HttpClient class now also offers support for HTTPS-based proxies.
  • If HTTP.sys is used as a web server in Windows, developers can activate response buffering in the Windows kernel. Microsoft claims: "In affected scenarios, this can drastically reduce response times from minutes (or complete failure) to seconds."
  • Redis could already be used for distributed caching in ASP.NET Core In .NET 8.0, Microsoft enables Redis for the web server output caching introduced in ASP.NET Core 7.0 with the NuGet package Microsoft.Extensions.Caching.StackExchangeRedis and the start code call services.AddStackExchangeRedisOutputCache().
  • SHA-3 is now also offered for the hashing classes in System.Security. The new classes are called SDA3_256, SHA3_386 and SHA3_512 in addition to the previous classes SDA_256, SHA_386 and SHA_512.
  • Microsoft improved the debugger view for some ASP.NET Core classes in .NET 8.0 Preview 5. They now display some of the essential data instead of the class name (Fig. 2).

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK