diff --git a/docs/architecture/maui/authentication-and-authorization.md b/docs/architecture/maui/authentication-and-authorization.md index d3b725fe761b6..fbc58e8251ef3 100644 --- a/docs/architecture/maui/authentication-and-authorization.md +++ b/docs/architecture/maui/authentication-and-authorization.md @@ -3,7 +3,7 @@ title: Authentication and Authorization description: Providing security and identity management for .NET MAUI application author: michaelstonis no-loc: [MAUI] -ms.date: 05/30/2024 +ms.date: 09/10/2024 --- # Authentication and authorization @@ -46,7 +46,7 @@ The eShop multi-platform app communicates with the identity microservice, which ### Adding IdentityServer to a web application In order for an ASP.NET Core web application to use IdentityServer, it must be added to the web application's Visual Studio solution. For more information, see [Setup and Overview](https://docs.duendesoftware.com/identityserver/v7/quickstarts/) in the IdentityServer documentation. -Once IdentityServer is included in the web application's Visual Studio solution, it must be added to its HTTP request processing pipeline to serve requests to OpenID Connect and OAuth 2.0 endpoints. This is configured in the `Identity.API` project's `Program.cs`, as demonstrated in the following code example: +Once IdentityServer is included in the web application's Visual Studio solution, it must be added to its HTTP request processing pipeline to serve requests to OpenID Connect and OAuth 2.0 endpoints. This is configured in the `Identity.API` project's _Program.cs_, as demonstrated in the following code example: ```csharp @@ -59,23 +59,28 @@ Order matters in the web application's HTTP request processing pipeline. Therefo ### Configuring IdentityServer -IdentityServer should be configured in the ConfigureServices method in the web application's Startup class by calling the `services.AddIdentityServer` method, as demonstrated in the following code example from the eShop reference application: +IdentityServer is configured in the `Identity.API` project's _Program.cs_ by calling the `AddIdentityServer` method, as demonstrated in the following code example from the eShop reference application: ```csharp -public void ConfigureServices(IServiceCollection services) -{ -    services - .AddIdentityServer(x => x.IssuerUri = "null") -        .AddSigningCredential(Certificate.Get()) -        .AddAspNetIdentity() -        .AddConfigurationStore(builder => -            builder.UseSqlServer(connectionString, options => -                options.MigrationsAssembly(migrationsAssembly))) -        .AddOperationalStore(builder => -            builder.UseSqlServer(connectionString, options => -                options.MigrationsAssembly(migrationsAssembly))) -        .Services.AddTransient(); -} +builder.Services.AddIdentityServer(options => + { + options.Authentication.CookieLifetime = TimeSpan.FromHours(2); + + options.Events.RaiseErrorEvents = true; + options.Events.RaiseInformationEvents = true; + options.Events.RaiseFailureEvents = true; + options.Events.RaiseSuccessEvents = true; + + // TODO: Remove this line in production. + options.KeyManagement.Enabled = false; + }) + .AddInMemoryIdentityResources(Config.GetResources()) + .AddInMemoryApiScopes(Config.GetApiScopes()) + .AddInMemoryApiResources(Config.GetApis()) + .AddInMemoryClients(Config.GetClients(builder.Configuration)) + .AddAspNetIdentity() + // TODO: Not recommended for production - you need to store your key material somewhere secure + .AddDeveloperSigningCredential(); ``` After calling the `services.AddIdentityServer` method, additional fluent APIs are called to configure the following: @@ -147,33 +152,37 @@ public static IEnumerable GetClients(Dictionary clien     return new List     {         // Omitted for brevity -        new Client -        { -            ClientId = "maui", -            ClientName = "eShop .NET MAUI OpenId Client", -            AllowedGrantTypes = GrantTypes.Hybrid, -            ClientSecrets = -            { -                new Secret("secret".Sha256()) -            }, -            RedirectUris = { clientsUrl["maui"] }, -            RequireConsent = false, -            RequirePkce = true, -            PostLogoutRedirectUris = { $"{clientsUrl["maui"]}/Account/Redirecting" }, -            AllowedCorsOrigins = { "http://eshopmaui" }, -            AllowedScopes = new List -            { -                IdentityServerConstants.StandardScopes.OpenId, -                IdentityServerConstants.StandardScopes.Profile, -                IdentityServerConstants.StandardScopes.OfflineAccess, -                "orders", -                "basket" -            }, -            AllowOfflineAccess = true, -            AllowAccessTokensViaBrowser = true, + new Client + { + ClientId = "maui", + ClientName = "eShop MAUI OpenId Client", + AllowedGrantTypes = GrantTypes.Code, + //Used to retrieve the access token on the back channel. + ClientSecrets = + { + new Secret("secret".Sha256()) + }, + RedirectUris = { configuration["MauiCallback"] }, + RequireConsent = false, + RequirePkce = true, + PostLogoutRedirectUris = { $"{configuration["MauiCallback"]}/Account/Redirecting" }, + AllowedScopes = new List + { + IdentityServerConstants.StandardScopes.OpenId, + IdentityServerConstants.StandardScopes.Profile, + IdentityServerConstants.StandardScopes.OfflineAccess, + "orders", + "basket", + "mobileshoppingagg", + "webhooks" + }, + //Allow requesting refresh tokens for long lived API access + AllowOfflineAccess = true, + AllowAccessTokensViaBrowser = true, + AlwaysIncludeUserClaimsInIdToken = true, AccessTokenLifetime = 60 * 60 * 2, // 2 hours IdentityTokenLifetime = 60 * 60 * 2 // 2 hours -        } + }     }; } ``` diff --git a/docs/architecture/maui/mvvm.md b/docs/architecture/maui/mvvm.md index a6c8d135674b8..9c74f8ec418c1 100644 --- a/docs/architecture/maui/mvvm.md +++ b/docs/architecture/maui/mvvm.md @@ -3,7 +3,7 @@ title: Model-View-ViewModel description: Overview of the Model-View-ViewModel pattern used by .NET MAUI author: michaelstonis no-loc: [MAUI] -ms.date: 05/30/2024 +ms.date: 09/10/2024 --- # Model-View-ViewModel (MVVM) @@ -339,7 +339,7 @@ The advantage of using the `EventToCommandBehavior` to execute a command when an ## Invoking behaviors from a view -The EventToCommandBehavior is particularly useful for attaching a command to a control that doesn't support commands. For example, the LoginView uses the `EventToCommandBehavior` to execute the `ValidateCommand` when the user changes the value of their password, as shown in the following code: +The `EventToCommandBehavior` is particularly useful for attaching a command to a control that doesn't support commands. For example, the LoginView uses the `EventToCommandBehavior` to execute the `ValidateCommand` when the user changes the value of their password, as shown in the following code: ```xaml (options => { - options.UseSqlServer(builder.Configuration["ConnectionString"], - sqlServerOptionsAction: sqlOptions => - { - sqlOptions.EnableRetryOnFailure( - maxRetryCount: 10, - maxRetryDelay: TimeSpan.FromSeconds(30), - errorNumbersToAdd: null); - }); + options.UseSqlServer( + builder.Configuration["ConnectionString"], + sqlServerOptionsAction: sqlOptions => + { + sqlOptions.EnableRetryOnFailure( + maxRetryCount: 10, + maxRetryDelay: TimeSpan.FromSeconds(30), + errorNumbersToAdd: null); + }); }); ``` +[!INCLUDE [managed-identities](../../../framework/includes/managed-identities.md)] + ## Execution strategies and explicit transactions using BeginTransaction and multiple DbContexts When retries are enabled in EF Core connections, each operation you perform using EF Core becomes its own retryable operation. Each query and each call to `SaveChanges` will be retried as a unit if a transient failure occurs. diff --git a/docs/architecture/microservices/implement-resilient-applications/monitor-app-health.md b/docs/architecture/microservices/implement-resilient-applications/monitor-app-health.md index 78862829e9bcc..667a3a8e28240 100644 --- a/docs/architecture/microservices/implement-resilient-applications/monitor-app-health.md +++ b/docs/architecture/microservices/implement-resilient-applications/monitor-app-health.md @@ -1,7 +1,7 @@ --- title: Health monitoring description: Explore one way of implementing health monitoring. -ms.date: 06/23/2021 +ms.date: 09/10/2024 --- # Health monitoring @@ -97,6 +97,8 @@ public class SqlConnectionHealthCheck : IHealthCheck } ``` +[!INCLUDE [managed-identities](../../../framework/includes/managed-identities.md)] + Note that in the previous code, `Select 1` is the query used to check the Health of the database. To monitor the availability of your microservices, orchestrators like Kubernetes periodically perform health checks by sending requests to test the microservices. It's important to keep your database queries efficient so that these operations are quick and don’t result in a higher utilization of resources. Finally, add a middleware that responds to the url path `/hc`: diff --git a/docs/architecture/microservices/microservice-ddd-cqrs-patterns/cqrs-microservice-reads.md b/docs/architecture/microservices/microservice-ddd-cqrs-patterns/cqrs-microservice-reads.md index 24cb47433569d..e84c0a59a8b0f 100644 --- a/docs/architecture/microservices/microservice-ddd-cqrs-patterns/cqrs-microservice-reads.md +++ b/docs/architecture/microservices/microservice-ddd-cqrs-patterns/cqrs-microservice-reads.md @@ -109,7 +109,7 @@ using System.Collections.Generic; public class OrderQueries : IOrderQueries { - public async Task> GetOrdersAsync() + public async Task> GetOrdersAsync() { using (var connection = new SqlConnection(_connectionString)) { diff --git a/docs/architecture/microservices/microservice-ddd-cqrs-patterns/nosql-database-persistence-infrastructure.md b/docs/architecture/microservices/microservice-ddd-cqrs-patterns/nosql-database-persistence-infrastructure.md index d0794492a8c3e..f136571ab97f3 100644 --- a/docs/architecture/microservices/microservice-ddd-cqrs-patterns/nosql-database-persistence-infrastructure.md +++ b/docs/architecture/microservices/microservice-ddd-cqrs-patterns/nosql-database-persistence-infrastructure.md @@ -1,7 +1,7 @@ --- title: Using NoSQL databases as a persistence infrastructure description: Understand the use of NoSql databases in general, and Azure Cosmos DB in particular, as an option to implement persistence. -ms.date: 06/23/2021 +ms.date: 09/10/2024 --- # Use NoSQL databases as a persistence infrastructure @@ -275,6 +275,8 @@ services: - ConnectionString=${ESHOP_AZURE_COSMOSDB:-mongodb://nosqldata} ``` +[!INCLUDE [managed-identities](../../../framework/includes/managed-identities.md)] + The `ConnectionString` environment variable is resolved this way: If the `ESHOP_AZURE_COSMOSDB` global variable is defined in the `.env` file with the Azure Cosmos DB connection string, it will use it to access the Azure Cosmos DB database in the cloud. If it’s not defined, it will take the `mongodb://nosqldata` value and use the development MongoDB container. The following code shows the `.env` file with the Azure Cosmos DB connection string global environment variable, as implemented in eShopOnContainers: diff --git a/docs/architecture/microservices/multi-container-microservice-net-applications/data-driven-crud-microservice.md b/docs/architecture/microservices/multi-container-microservice-net-applications/data-driven-crud-microservice.md index e3fcd727dfccb..adb51db3ff737 100644 --- a/docs/architecture/microservices/multi-container-microservice-net-applications/data-driven-crud-microservice.md +++ b/docs/architecture/microservices/multi-container-microservice-net-applications/data-driven-crud-microservice.md @@ -1,7 +1,7 @@ --- title: Creating a simple data-driven CRUD microservice description: .NET Microservices Architecture for Containerized .NET Applications | Understand the creation of a simple CRUD (data-driven) microservice within the context of a microservices application. -ms.date: 03/04/2024 +ms.date: 09/10/2024 --- # Creating a simple data-driven CRUD microservice @@ -211,6 +211,8 @@ builder.Services.AddDbContext(options => }); ``` +[!INCLUDE [managed-identities](../../../framework/includes/managed-identities.md)] + ### Additional resources - **Querying Data** \ @@ -254,9 +256,11 @@ catalog-api: - "5101:80" ``` +[!INCLUDE [managed-identities](../../../framework/includes/managed-identities.md)] + The docker-compose.yml files at the solution level are not only more flexible than configuration files at the project or microservice level, but also more secure if you override the environment variables declared at the docker-compose files with values set from your deployment tools, like from Azure DevOps Services Docker deployment tasks. -Finally, you can get that value from your code by using `builder.Configuration\["ConnectionString"\]`, as shown in an earlier code example. +Finally, you can get that value from your code by using `builder.Configuration["ConnectionString"]`, as shown in an earlier code example. However, for production environments, you might want to explore additional ways on how to store secrets like the connection strings. An excellent way to manage application secrets is using [Azure Key Vault](https://azure.microsoft.com/services/key-vault/). @@ -275,9 +279,7 @@ As business requirements change, new collections of resources may be added, the Versioning enables a Web API to indicate the features and resources that it exposes. A client application can then submit requests to a specific version of a feature or resource. There are several approaches to implement versioning: - URI versioning - - Query string versioning - - Header versioning Query string and URI versioning are the simplest to implement. Header versioning is a good approach. However, header versioning is not as explicit and straightforward as URI versioning. Because URL versioning is the simplest and most explicit, the eShopOnContainers sample application uses URI versioning. diff --git a/docs/architecture/microservices/multi-container-microservice-net-applications/test-aspnet-core-services-web-apps.md b/docs/architecture/microservices/multi-container-microservice-net-applications/test-aspnet-core-services-web-apps.md index 07373e26cd7ab..ca09c182c0e72 100644 --- a/docs/architecture/microservices/multi-container-microservice-net-applications/test-aspnet-core-services-web-apps.md +++ b/docs/architecture/microservices/multi-container-microservice-net-applications/test-aspnet-core-services-web-apps.md @@ -176,7 +176,7 @@ services: - "5672:5672" sqldata: environment: - - SA_PASSWORD=Pass@word + - SA_PASSWORD=[PLACEHOLDER] - ACCEPT_EULA=Y ports: - "5433:1433" @@ -185,6 +185,8 @@ services: - "27017:27017" ``` +[!INCLUDE [managed-identities](../../../framework/includes/managed-identities.md)] + So, to run the functional/integration tests you must first run this command, from the solution test folder: ```console diff --git a/docs/core/deploying/native-aot/intrinsic-requiresdynamiccode-apis.md b/docs/core/deploying/native-aot/intrinsic-requiresdynamiccode-apis.md new file mode 100644 index 0000000000000..17a7517ba214b --- /dev/null +++ b/docs/core/deploying/native-aot/intrinsic-requiresdynamiccode-apis.md @@ -0,0 +1,68 @@ +--- +title: Intrinsic APIs marked RequiresDynamicCode +description: Learn how the tooling recognizes certain patterns in calls to APIs annotated with RequiresDynamicCode. +author: MichalStrehovsky +ms.author: michals +ms.date: 09/09/2024 +--- + +# Intrinsic APIs marked RequiresDynamicCode + +Under normal circumstances, calling APIs annotated with in an app published with native AOT triggers warning [IL3050 (Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as native AOT)](warnings/il3050.md). APIs that trigger the warning might not behave correctly after AOT compilation. + +Some APIs annotated RequiresDynamicCode can still be used without triggering the warning when called in a specific pattern. When used as part of a pattern, the call to the API can be statically analyzed by the compiler, does not generate a warning, and behaves as expected at run time. + +## Enum.GetValues(Type) Method + +Calls to this API don't trigger a warning if the concrete enum type is statically visible in the calling method body. For example, `Enum.GetValues(typeof(AttributeTargets))` does not trigger a warning, but `Enum.GetValues(typeof(T))` and `Enum.GetValues(someType)` do. + +## Marshal.DestroyStructure(IntPtr, Type) Method + +Calls to this API don't trigger a warning if the concrete type is statically visible in the calling method body. For example, `Marshal.DestroyStructure(offs, typeof(bool))` does not trigger a warning, but `Marshal.DestroyStructure(offs, typeof(T))` and `Marshal.DestroyStructure(offs, someType)` do. + +## Marshal.GetDelegateForFunctionPointer(IntPtr, Type) Method + +Calls to this API don't trigger a warning if the concrete type is statically visible in the calling method body. For example, `Marshal.GetDelegateForFunctionPointer(ptr, typeof(bool))` does not trigger a warning, but `Marshal.GetDelegateForFunctionPointer(ptr, typeof(T))` and `Marshal.GetDelegateForFunctionPointer(ptr, someType)` do. + +## Marshal.OffsetOf(Type, String) Method + +Calls to this API don't trigger a warning if the concrete type is statically visible in the calling method body. For example, `Marshal.OffsetOf(typeof(Point), someField)` does not trigger a warning, but `Marshal.OffsetOf(typeof(T), someField)` and `Marshal.OffsetOf(someType, someField)` do. + +## Marshal.PtrToStructure(IntPtr, Type) Method + +Calls to this API don't trigger a warning if the concrete type is statically visible in the calling method body. For example, `Marshal.PtrToStructure(offs, typeof(bool))` does not trigger a warning, but `Marshal.PtrToStructure(offs, typeof(T))` and `Marshal.PtrToStructure(offs, someType)` do. + +## Marshal.SizeOf(Type) Method + +Calls to this API don't trigger a warning if the concrete type is statically visible in the calling method body. For example, `Marshal.SizeOf(typeof(bool))` does not trigger a warning, but `Marshal.SizeOf(typeof(T))` and `Marshal.SizeOf(someType)` do. + +## MethodInfo.MakeGenericMethod(Type[]) Method (.NET 9+) + +Calls to this API don't trigger a warning if both the generic method definition and the instantiation arguments are statically visible within the calling method body. For example, `typeof(SomeType).GetMethod("GenericMethod").MakeGenericMethod(typeof(int))`. It's also possible to use a generic parameter as the argument: `typeof(SomeType).GetMethod("GenericMethod").MakeGenericMethod(typeof(T))` also doesn't warn. + +If the generic type definition is statically visible within the calling method body and all the generic parameters of it are constrained to be a class, the call also doesn't trigger the IL3050 warning. In this case, the arguments don't have to be statically visible. For example: + +```csharp +// No IL3050 warning on MakeGenericMethod because T is constrained to be class +typeof(SomeType).GetMethod("GenericMethod").MakeGenericMethod(Type.GetType(Console.ReadLine())); +class SomeType +{ + public void GenericMethod() where T : class { } +} +``` + +All the other cases, such as `someMethod.MakeGenericMethod(typeof(int))` or `typeof(SomeType).GetMethod("GenericMethod").MakeGenericMethod(someType)` where `someType` has an unknown value, trigger a warning. + +## Type.MakeGenericType(Type[]) Method (.NET 9+) + +Calls to this API don't trigger a warning if both the generic type definition and the instantiation arguments are statically visible within the calling method body. For example, `typeof(List<>).MakeGenericType(typeof(int))`. It's also possible to use a generic parameter as the argument: `typeof(List<>).MakeGenericType(typeof(T))` also doesn't warn. + +If the generic type definition is statically visible within the calling method body and all the generic parameters of it are constrained to be a class, the call also doesn't trigger the IL3050 warning. In this case, the arguments don't have to be statically visible. For example: + +```csharp +// No IL3050 warning on MakeGenericType because T is constrained to be class +typeof(Generic<>).MakeGenericType(Type.GetType(Console.ReadLine())); +class Generic where T : class { } +``` + +All the other cases, such as `someType.MakeGenericType(typeof(int))` or `typeof(List<>).MakeGenericType(someType)` where `someType` has an unknown value, trigger a warning. diff --git a/docs/core/deploying/native-aot/warnings/il3050.md b/docs/core/deploying/native-aot/warnings/il3050.md index b982ace3bb53d..b5d5213ca37ba 100644 --- a/docs/core/deploying/native-aot/warnings/il3050.md +++ b/docs/core/deploying/native-aot/warnings/il3050.md @@ -23,7 +23,7 @@ When you publish an app as Native AOT (by setting the `PublishAot` property to ` // AOT analysis warning IL3050: Program.
$(String[]): Using member 'System.Type.MakeGenericType(Type[])' // which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. The native code for // this instantiation might not be available at runtime. -typeof(Generic<>).MakeGenericType(typeof(SomeStruct)); +typeof(Generic<>).MakeGenericType(unknownType); class Generic { } @@ -33,3 +33,5 @@ struct SomeStruct { } ## How to fix violations Members annotated with the `RequiresDynamicCodeAttribute` attribute have a message that provides useful information to users who are publishing as Native AOT. Consider adapting existing code to the attribute's message or removing the violating call. + +Some APIs annotated with `RequiresDynamicCodeAttribute` don't trigger a warning when called in a specific pattern. For more information, see [Intrinsic APIs marked RequiresDynamicCode](../intrinsic-requiresdynamiccode-apis.md). diff --git a/docs/core/extensions/configuration-providers.md b/docs/core/extensions/configuration-providers.md index d68566bbc02d5..8b3fb07bf498b 100644 --- a/docs/core/extensions/configuration-providers.md +++ b/docs/core/extensions/configuration-providers.md @@ -3,7 +3,7 @@ title: Configuration providers description: Discover how to configure .NET apps using the configuration provider API and the available configuration providers. author: IEvangelist ms.author: dapine -ms.date: 06/23/2023 +ms.date: 09/10/2024 --- # Configuration providers in .NET @@ -228,6 +228,8 @@ When an environment variable is discovered and loaded into configuration with an | `SQLAZURECONNSTR_{KEY}` | `ConnectionStrings:{KEY}` | Key: `ConnectionStrings:{KEY}_ProviderName`:
Value: `System.Data.SqlClient` | | `SQLCONNSTR_{KEY}` | `ConnectionStrings:{KEY}` | Key: `ConnectionStrings:{KEY}_ProviderName`:
Value: `System.Data.SqlClient` | +[!INCLUDE [managed-identities](../../framework/includes/managed-identities.md)] + ### Environment variables set in launchSettings.json Environment variables set in *launchSettings.json* override those set in the system environment. diff --git a/docs/core/tools/dotnet-workload-install.md b/docs/core/tools/dotnet-workload-install.md index bf722ba093403..3ffd14d09beaa 100644 --- a/docs/core/tools/dotnet-workload-install.md +++ b/docs/core/tools/dotnet-workload-install.md @@ -2,6 +2,7 @@ title: dotnet workload install command description: The 'dotnet workload install' command installs optional workloads. ms.date: 09/10/2021 +no-loc: [dotnet workload install] --- # dotnet workload install diff --git a/docs/core/whats-new/dotnet-9/libraries.md b/docs/core/whats-new/dotnet-9/libraries.md index 12e984fc3f0d5..13e8f3e65665d 100644 --- a/docs/core/whats-new/dotnet-9/libraries.md +++ b/docs/core/whats-new/dotnet-9/libraries.md @@ -2,12 +2,13 @@ title: What's new in .NET libraries for .NET 9 description: Learn about the new .NET libraries features introduced in .NET 9. titleSuffix: "" -ms.date: 08/09/2024 +ms.date: 09/09/2024 ms.topic: whats-new --- + # What's new in .NET libraries for .NET 9 -This article describes new features in the .NET libraries for .NET 9. It's been updated for .NET 9 Preview 7. +This article describes new features in the .NET libraries for .NET 9. It's been updated for .NET 9 RC 1. ## Base64Url @@ -22,7 +23,7 @@ string encoded = Base64Url.EncodeToString(bytes); ## BinaryFormatter -.NET 9 removes from the .NET runtime. The APIs are still present, but their implementations always throw an exception, regardless of project type. For more information about the removal and your options if you're affected, see [BinaryFormatter migration guide](../../../standard/serialization/binaryformatter-migration-guide/index.md). +.NET 9 removes from the .NET runtime. The APIs are still present, but their implementations always throw an exception, regardless of project type. For more information about the removal and your options if you're affected, see [BinaryFormatter migration guide](../../../standard/serialization/binaryformatter-migration-guide/index.md). ## Collections @@ -37,7 +38,7 @@ The collection types in .NET gain the following updates for .NET 9: In high-performance code, spans are often used to avoid allocating strings unnecessarily, and lookup tables with types like and are frequently used as caches. However, there has been no safe, built-in mechanism for doing lookups on these collection types with spans. With the new `allows ref struct` feature in C# 13 and new features on these collection types in .NET 9, it's now possible to perform these kinds of lookups. -The following example demonstrates using `Dictionary.GetAlternateLookup()` . +The following example demonstrates using [Dictionary.GetAlternateLookup](xref:System.Collections.Generic.CollectionExtensions.GetAlternateLookup%60%603(System.Collections.Generic.Dictionary{%60%600,%60%601})). :::code language="csharp" source="../snippets/dotnet-9/csharp/Collections.cs" id="AlternateLookup"::: @@ -131,13 +132,13 @@ Those methods all used content-sniffing to figure out if the input was something - It's a protocol deviation. - It's a source of security issues. -.NET 9 introduces a new `X509CertificateLoader` class, which has a "one method, one purpose" design. In its initial version, it only supports two of the five formats that the constructor supported. Those are the two formats that worked on all operation systems. +.NET 9 introduces a new class, which has a "one method, one purpose" design. In its initial version, it only supports two of the five formats that the constructor supported. Those are the two formats that worked on all operation systems. ### OpenSSL providers support .NET 8 introduced the OpenSSL-specific APIs and . They enable interacting with OpenSSL [`ENGINE` components](https://github.com/openssl/openssl/blob/master/README-ENGINES.md) and use hardware security modules (HSM), for example. -.NET 9 introduces `SafeEvpPKeyHandle.OpenKeyFromProvider`, which enables using [OpenSSL providers](https://docs.openssl.org/master/man7/provider/) and interacting with providers such as `tpm2` or `pkcs11`. +.NET 9 introduces , which enables using [OpenSSL providers](https://docs.openssl.org/master/man7/provider/) and interacting with providers such as `tpm2` or `pkcs11`. Some distros have [removed `ENGINE` support](https://github.com/dotnet/runtime/issues/104775) since it is now deprecated. @@ -161,7 +162,7 @@ There are some performance improvements during the TLS handshake as well as impr Windows 11 has added new APIs to help secure Windows keys with [virtualization-based security (VBS)](https://techcommunity.microsoft.com/t5/windows-it-pro-blog/advancing-key-protection-in-windows-using-vbs/ba-p/4050988). With this new capability, keys can be protected from admin-level key theft attacks with negligible effect on performance, reliability, or scale. -.NET 9 has added matching `CngKeyCreationOptions` flags. The following three flags were added: +.NET 9 has added matching flags. The following three flags were added: - `CngKeyCreationOptions.PreferVbs` matching `NCRYPT_PREFER_VBS_FLAG` - `CngKeyCreationOptions.RequireVbs` matching `NCRYPT_REQUIRE_VBS_FLAG` @@ -202,6 +203,7 @@ The constructor resolution for event source provider, but prior to .NET 9, you had to specify the full meter name. In .NET 9, you can listen to all meters by using the wildcard character `*`, which allows you to capture metrics from every meter in a process. Additionally, it adds support for listening by meter prefix, so you can listen to all meters whose names start with a specified prefix. For example, specifying `MyMeter*` enables listening to all meters with names that begin with `MyMeter`. + +:::code language="csharp" source="../snippets/dotnet-9/csharp/Diagnostics.cs" id="Wildcard"::: + +The `MyEventListener` class is defined as follows. + +:::code language="csharp" source="../snippets/dotnet-9/csharp/Diagnostics.cs" id="EventListener"::: + +When you execute the code, the output is as follows: + +```txt +CounterRateValuePublished + sessionId: 7cd94a65-0d0d-460e-9141-016bf390d522 + meterName: MyCompany.MyMeter + meterVersion: + instrumentName: MyCounter + unit: + tags: + rate: 0 + value: 1 + instrumentId: 1 +CounterRateValuePublished + sessionId: 7cd94a65-0d0d-460e-9141-016bf390d522 + meterName: MyCompany.MyMeter + meterVersion: + instrumentName: MyCounter + unit: + tags: + rate: 0 + value: 1 + instrumentId: 1 +``` + +You can also use the wildcard character to listen to metrics with monitoring tools like [dotnet-counters](../../diagnostics/dotnet-counters.md). + ## LINQ New methods and have been introduced. These methods make it possible to aggregate state by key without needing to allocate intermediate groupings via . @@ -310,6 +349,8 @@ This new capability has an optimized implementation that takes advantage of the - [SocketsHttpHandler is default in HttpClientFactory](#socketshttphandler-is-default-in-httpclientfactory) - [System.Net.ServerSentEvents](#systemnetserversentevents) - [TLS resume with client certificates on Linux](#tls-resume-with-client-certificates-on-linux) +- [WebSocket keep-alive ping and timeout](#websocket-keep-alive-ping-and-timeout) +- [HttpClientFactory no longer logs header values by default](#httpclientfactory-no-longer-logs-header-values-by-default) ### SocketsHttpHandler is default in HttpClientFactory @@ -325,9 +366,32 @@ The following code demonstrates using the new class. ### TLS resume with client certificates on Linux -*TLS resume* is a feature of the TLS protocol that allows resuming previously established sessions to a server. Doing so avoids a few roundtrips and saves computational resources during TLS handshake. +_TLS resume_ is a feature of the TLS protocol that allows resuming previously established sessions to a server. Doing so avoids a few roundtrips and saves computational resources during TLS handshake. + +_TLS resume_ has already been supported on Linux for SslStream connections without client certificates. .NET 9 adds support for TLS resume of mutually authenticated TLS connections, which are common in server-to-server scenarios. The feature is enabled automatically. + +### WebSocket keep-alive ping and timeout + +New APIs on and let you opt in to sending pings and aborting the connection if the peer doesn't respond in time. -*TLS resume* has already been supported on Linux for SslStream connections without client certificates. .NET 9 adds support for TLS resume of mutually authenticated TLS connections, which are common in server-to-server scenarios. The feature is enabled automatically. +Until now, you could specify a to keep the connection from staying idle, but there was no built-in mechanism to enforce that the peer is responding. + +The following example pings the server every 5 seconds and aborts the connection if it doesn't respond within a second. + +:::code language="csharp" source="../snippets/dotnet-9/csharp/Networking.cs" id="KeepAliveTimeout"::: + +### HttpClientFactory no longer logs header values by default + + events logged by `HttpClientFactory` no longer include header values by default. You can opt in to logging values for specific headers via the helper method. + +The following example redacts all headers, except for the user agent. + +```csharp +services.AddHttpClient("myClient") + .RedactLoggedHeaders(name => name != "User-Agent"); +``` + +For more information, see [HttpClientFactory logging redacts header values by default](../../compatibility/networking/9.0/redact-headers.md). ## Reflection @@ -336,7 +400,7 @@ The following code demonstrates using the new class. ### Persisted assemblies -In .NET Core versions and .NET 5-8, support for building an assembly and emitting reflection metadata for dynamically created types was limited to a runnable . The lack of support for *saving* an assembly was often a blocker for customers migrating from .NET Framework to .NET. .NET 9 adds a new type, , that you can use to save an emitted assembly. +In .NET Core versions and .NET 5-8, support for building an assembly and emitting reflection metadata for dynamically created types was limited to a runnable . The lack of support for _saving_ an assembly was often a blocker for customers migrating from .NET Framework to .NET. .NET 9 adds a new type, , that you can use to save an emitted assembly. To create a `PersistedAssemblyBuilder` instance, call its constructor and pass the assembly name, the core assembly, `System.Private.CoreLib`, to reference base runtime types, and optional custom attributes. After you emit all members to the assembly, call the method to create an assembly with default settings. If you want to set the entry point or other options, you can call and use the metadata it returns to save the assembly. The following code shows an example of creating a persisted assembly and setting the entry point. @@ -359,7 +423,7 @@ The new `TypeName` class provides: - `IsByRef` and `IsPointer` for working with pointers and managed references. - `GetElementType()` for working with pointers, references, and arrays. - `IsNested` and `DeclaringType` for working with nested types. - - `AssemblyName`, which exposes the assembly name information via the new class. In contrast to `AssemblyName`, the new type is *immutable*, and parsing culture names doesn't create instances of `CultureInfo`. + - `AssemblyName`, which exposes the assembly name information via the new class. In contrast to `AssemblyName`, the new type is _immutable_, and parsing culture names doesn't create instances of `CultureInfo`. Both `TypeName` and `AssemblyNameInfo` types are immutable and don't provide a way to check for equality (they don't implement `IEquatable`). Comparing assembly names is simple, but different scenarios need to compare only a subset of exposed information (`Name`, `Version`, `CultureName`, and `PublicKeyOrToken`). @@ -382,7 +446,7 @@ The following partial method will be source generated with all the code necessar :::code language="csharp" source="../snippets/dotnet-9/csharp/RegularExpressions.cs" id="GeneratedRegexMethod"::: -C# 13 supports partial *properties* in addition to partial methods, so starting in .NET 9 you can also use `[GeneratedRegex(...)]` on a property. +C# 13 supports partial _properties_ in addition to partial methods, so starting in .NET 9 you can also use `[GeneratedRegex(...)]` on a property. The following partial property is the property equivalent of the previous example. @@ -440,24 +504,18 @@ The generated schema is: ```json { - "type": [ - "object", - "null" - ], - "properties": { - "Title": { - "type": "string" - }, - "Author": { - "type": [ - "string", - "null" - ] - }, - "PublishYear": { - "type": "integer" + "type": ["object", "null"], + "properties": { + "Title": { + "type": "string" + }, + "Author": { + "type": ["string", "null"] + }, + "PublishYear": { + "type": "integer" + } } - } } ``` @@ -469,7 +527,7 @@ The following code shows how to set the option (the `Book` type definition is sh :::code language="csharp" source="../snippets/dotnet-9/csharp/Serialization.cs" id="RespectNullable"::: -You can also enable this setting globally using the `System.Text.Json.JsonSerializerOptions.RespectNullableAnnotations` feature switch in your project file (for example, *.csproj* file): +You can also enable this setting globally using the `System.Text.Json.JsonSerializerOptions.RespectNullableAnnotations` feature switch in your project file (for example, _.csproj_ file): ```xml @@ -491,7 +549,7 @@ The `MyPoco` type is defined as follows: :::code language="csharp" source="../snippets/dotnet-9/csharp/Serialization.cs" id="Poco"::: -You can also enable this setting globally using the `System.Text.Json.JsonSerializerOptions.RespectRequiredConstructorParameters` feature switch in your project file (for example, *.csproj* file): +You can also enable this setting globally using the `System.Text.Json.JsonSerializerOptions.RespectRequiredConstructorParameters` feature switch in your project file (for example, _.csproj_ file): ```xml @@ -594,7 +652,7 @@ Now, a call like `string.Join(", ", "a", "b", "c")` is made without allocating a In .NET 8, a set of `Split` and `SplitAny` methods were introduced for `ReadOnlySpan`. Rather than returning a new `string[]`, these methods accept a destination `Span` into which the bounding indices for each component are written. This makes the operation fully allocation-free. These methods are appropriate to use when the number of ranges is both known and small. -In .NET 9, new overloads of `Split` and `SplitAny` have been added to allow incrementally parsing a `ReadOnlySpan` with an *a priori* unknown number of segments. The new methods enable enumerating through each segment, which is similarly represented as a `Range` that can be used to slice into the original span. +In .NET 9, new overloads of `Split` and `SplitAny` have been added to allow incrementally parsing a `ReadOnlySpan` with an _a priori_ unknown number of segments. The new methods enable enumerating through each segment, which is similarly represented as a `Range` that can be used to slice into the original span. ```csharp public static bool ListContainsItem(ReadOnlySpan span, string item) @@ -611,22 +669,39 @@ public static bool ListContainsItem(ReadOnlySpan span, string item) } ``` +## System.Formats + +The position or offset of the data in the enclosing stream for a object is now a public property. `TarEntry.DataOffset` returns the position in the entry's archive stream where the entry's first data byte is located. The entry's data is encapsulated in a substream that you can access via , which hides the real position of the data relative to the archive stream. That's enough for most users, but if you need more flexibility and want to know the real starting position of the data in the archive stream, the new `TarEntry.DataOffset` API makes it easy to support features like concurrent access with very large TAR files. + +:::code language="csharp" source="../snippets/dotnet-9/csharp/TarEntry.cs" id="DataOffset"::: + ## System.Guid - creates a `Guid` filled mostly with [cryptographically secure random data](https://www.rfc-editor.org/rfc/rfc9562#section-6.9), following the UUID Version 4 specification in RFC 9562. That same RFC also defines other versions, including Version 7, which "features a time-ordered value field derived from the widely implemented and well-known Unix Epoch timestamp source". In other words, much of the data is still random, but some of it is reserved for data based on a timestamp, which enables these values to have a natural sort order. In .NET 9, you can create a `Guid` according to Version 7 via the new `Guid.CreateVersion7()` and `Guid.CreateVersion7(DateTimeOffset timestamp)` methods. You can also use the new `Version` property to retrieve a `Guid` object's version field. + creates a `Guid` filled mostly with [cryptographically secure random data](https://www.rfc-editor.org/rfc/rfc9562#section-6.9), following the UUID Version 4 specification in RFC 9562. That same RFC also defines other versions, including Version 7, which "features a time-ordered value field derived from the widely implemented and well-known Unix Epoch timestamp source". In other words, much of the data is still random, but some of it is reserved for data based on a timestamp, which enables these values to have a natural sort order. In .NET 9, you can create a `Guid` according to Version 7 via the new and methods. You can also use the new property to retrieve a `Guid` object's version field. ## System.IO -- [Compression](#compression) +- [Compression with zlib-ng](#compression-with-zlib-ng) +- [ZLib and Brotli compression options](#zlib-and-brotli-compression-options) - [XPS documents from XPS virtual printer](#xps-documents-from-xps-virtual-printer) -### Compression +### Compression with zlib-ng features like , , , and are all based primarily on the zlib library. Starting in .NET 9, these features instead all use [zlib-ng](https://github.com/zlib-ng/zlib-ng), a library that yields more consistent and efficient processing across a wider array of operating systems and hardware. +### ZLib and Brotli compression options + +`ZLibCompressionOptions` and `BrotliCompressionOptions` are new types for setting algorithm-specific compression [level](xref:System.IO.Compression.CompressionLevel) and strategy (`Default`, `Filtered`, `HuffmanOnly`, `RunLengthEncoding`, or `Fixed`). These types are aimed at users who want more fine-tuned settings than the only existing option, . + +The new compression option types might be expanded in the future. + +The following code snippet shows some example usage: + +:::code language="csharp" source="../snippets/dotnet-9/csharp/Compression.cs" id="CompressStream"::: + ### XPS documents from XPS virtual printer -XPS documents coming from a V4 XPS virtual printer previously couldn't be opened using the library, due to lack of support for handling *.piece* files. This gap has been addressed in .NET 9. +XPS documents coming from a V4 XPS virtual printer previously couldn't be opened using the library, due to lack of support for handling _.piece_ files. This gap has been addressed in .NET 9. ## System.Numerics diff --git a/docs/core/whats-new/dotnet-9/overview.md b/docs/core/whats-new/dotnet-9/overview.md index f9cc6e096aadc..ec722083d484a 100644 --- a/docs/core/whats-new/dotnet-9/overview.md +++ b/docs/core/whats-new/dotnet-9/overview.md @@ -2,9 +2,10 @@ title: What's new in .NET 9 description: Learn about the new .NET features introduced in .NET 9 for the runtime, libraries, and SDK. Also find links to what's new in other areas, such as ASP.NET Core. titleSuffix: "" -ms.date: 08/15/2024 +ms.date: 09/10/2024 ms.topic: whats-new --- + # What's new in .NET 9 Learn about the new features in .NET 9 and find links to further documentation. @@ -17,7 +18,7 @@ New for .NET 9, the engineering team posts .NET 9 preview updates on [GitHub Dis The .NET 9 runtime includes a new attribute model for feature switches with trimming support. The new attributes make it possible to define [feature switches](https://github.com/dotnet/designs/blob/main/accepted/2020/feature-switch.md) that libraries can use to toggle areas of functionality. -Garbage collection includes a *dynamic adaptation to application size* feature that's used by default instead of Server GC. +Garbage collection includes a _dynamic adaptation to application size_ feature that's used by default instead of Server GC. The runtime also includes numerous performance improvements, including loop optimizations, inlining, and Arm64 vectorization and code generation. @@ -29,11 +30,11 @@ For more information, see [What's new in the .NET 9 runtime](runtime.md). In LINQ, the new methods and make it possible to aggregate state by key without needing to allocate intermediate groupings via . -For collection types, the type includes a new method that you can use to *update* the priority of an item in the queue. +For collection types, the type includes a new method that you can use to _update_ the priority of an item in the queue. For cryptography, .NET 9 adds a new one-shot hash method on the type. It also adds new classes that use the KMAC algorithm. -For reflection, the new type lets you *save* an emitted assembly. This new class also includes PDB support, meaning you can emit symbol info and use it to debug a generated assembly. +For reflection, the new type lets you _save_ an emitted assembly. This new class also includes PDB support, meaning you can emit symbol info and use it to debug a generated assembly. The class includes new `From*` methods that let you create a `TimeSpan` object from an `int` (instead of a `double`). These methods help to avoid errors caused by inherent imprecision in floating-point calculations. @@ -41,7 +42,14 @@ For more information, see [What's new in the .NET 9 libraries](libraries.md). ## .NET SDK -The .NET 9 SDK introduces *workload sets*, where all of your workloads stay at a single, specific version until explicitly updated. Unit testing has better MSBuild integration that allows you to run tests in parallel. For tools, a new option for [`dotnet tool install`](../../tools/dotnet-tool-install.md) lets users (instead of tool authors) decide whether a tool is allowed to run on a newer .NET runtime version than the version the tool targets. NuGet security audits run on both direct and transitive package references, by default. The terminal logger is now enabled by default and also has improved usability. For example, the total count of failures and warnings is now summarized at the end of a build. New MSBuild script analyzers are available. The SDK can detect and adjust for version mismatches between the .NET SDK and MSBuild. +The .NET 9 SDK introduces _workload sets_, where all of your workloads stay at a single, specific version until explicitly updated. For tools, a new option for [`dotnet tool install`](../../tools/dotnet-tool-install.md) lets users (instead of tool authors) decide whether a tool is allowed to run on a newer .NET runtime version than the version the tool targets. In addition: + +- Unit testing has better MSBuild integration that allows you to run tests in parallel. +- NuGet security audits run on both direct and transitive package references, by default. +- The terminal logger is enabled by default and also has improved usability. For example, the total count of failures and warnings is now summarized at the end of a build. +- New MSBuild script analyzers ("build checks") are available. +- The SDK can detect and adjust for version mismatches between the .NET SDK and MSBuild. +- The `dotnet workload history` command shows you the history of workload installations and modifications for the current .NET SDK installation. For more information, see [What's new in the SDK for .NET 9](sdk.md). diff --git a/docs/core/whats-new/dotnet-9/runtime.md b/docs/core/whats-new/dotnet-9/runtime.md index 794bb95c7295e..728a04e57de8b 100644 --- a/docs/core/whats-new/dotnet-9/runtime.md +++ b/docs/core/whats-new/dotnet-9/runtime.md @@ -2,7 +2,7 @@ title: What's new in .NET 9 runtime description: Learn about the new .NET features introduced in the .NET 9 runtime. titleSuffix: "" -ms.date: 08/08/2024 +ms.date: 09/09/2024 ms.topic: whats-new --- # What's new in the .NET 9 runtime diff --git a/docs/core/whats-new/dotnet-9/sdk.md b/docs/core/whats-new/dotnet-9/sdk.md index b9774009a9d3a..06f91e1620b6b 100644 --- a/docs/core/whats-new/dotnet-9/sdk.md +++ b/docs/core/whats-new/dotnet-9/sdk.md @@ -2,12 +2,13 @@ title: What's new in the SDK for .NET 9 description: Learn about the new .NET SDK features introduced in .NET 9, including for unit testing, terminal logger, tool roll-forward, and build script analyzers. titleSuffix: "" -ms.date: 08/15/2024 +ms.date: 09/09/2024 ms.topic: whats-new --- + # What's new in the SDK for .NET 9 -This article describes new features in the .NET SDK for .NET 9. It's been updated for .NET 9 Preview 7. +This article describes new features in the .NET SDK for .NET 9. It's been updated for .NET RC 1. ## Unit testing @@ -19,15 +20,15 @@ In .NET 9, `dotnet test` is more fully integrated with MSBuild. Because MSBuild ### Terminal logger test display -Test result reporting for [`dotnet test`](../../tools/dotnet-test.md) is now supported directly in the MSBuild terminal logger. You get more fully featured test reporting both *while* tests are running (displays the running test name) and *after* tests are completed (any test errors are rendered in a better way). +Test result reporting for [`dotnet test`](../../tools/dotnet-test.md) is now supported directly in the MSBuild terminal logger. You get more fully featured test reporting both _while_ tests are running (displays the running test name) and _after_ tests are completed (any test errors are rendered in a better way). For more information about the terminal logger, see [dotnet build options](../../tools/dotnet-build.md#options). ## .NET tool roll-forward -[.NET tools](../../tools/global-tools.md) are framework-dependent apps that you can install globally or locally, then run using the .NET SDK and installed .NET runtimes. These tools, like all .NET apps, target a specific major version of .NET. By default, apps don't run on *newer* versions of .NET. Tool authors have been able to opt in to running their tools on newer versions of the .NET runtime by setting the `RollForward` MSBuild property. However, not all tools do so. +[.NET tools](../../tools/global-tools.md) are framework-dependent apps that you can install globally or locally, then run using the .NET SDK and installed .NET runtimes. These tools, like all .NET apps, target a specific major version of .NET. By default, apps don't run on _newer_ versions of .NET. Tool authors have been able to opt in to running their tools on newer versions of the .NET runtime by setting the `RollForward` MSBuild property. However, not all tools do so. -A new option for [`dotnet tool install`](../../tools/dotnet-tool-install.md) lets *users* decide how .NET tools should be run. When you install a tool via `dotnet tool install`, or when you run tool via [`dotnet tool run `](../../tools/dotnet-tool-run.md), you can specify a new flag called `--allow-roll-forward`. This option configures the tool with roll-forward mode `Major`. This mode allows the tool to run on a newer major version of .NET if the matching .NET version is not available. This feature helps early adopters use .NET tools without tool authors having to change any code. +A new option for [`dotnet tool install`](../../tools/dotnet-tool-install.md) lets _users_ decide how .NET tools should be run. When you install a tool via `dotnet tool install`, or when you run tool via [`dotnet tool run `](../../tools/dotnet-tool-run.md), you can specify a new flag called `--allow-roll-forward`. This option configures the tool with roll-forward mode `Major`. This mode allows the tool to run on a newer major version of .NET if the matching .NET version is not available. This feature helps early adopters use .NET tools without tool authors having to change any code. ## Terminal logger @@ -77,7 +78,7 @@ Consider the following project file that emits a warning when the project is bui ``` -When you run `dotnet build -tl` on the .NET 8 SDK, the output is as shown following this paragraph. Each line of the multi-line warning is a separate line with a full error message prefix in the output, which is hard to read. Also, the final build summary says that there *were* warnings, but not *how many* there were. The missing information can make it hard to determine if a particular build is better or worse than previous builds. +When you run `dotnet build -tl` on the .NET 8 SDK, the output is as shown following this paragraph. Each line of the multi-line warning is a separate line with a full error message prefix in the output, which is hard to read. Also, the final build summary says that there _were_ warnings, but not _how many_ there were. The missing information can make it hard to determine if a particular build is better or worse than previous builds. ```terminal $ dotnet build -tl @@ -112,7 +113,7 @@ If you have feedback about the terminal logger, you can provide it in the [MSBui ## NuGet security audits -Starting in .NET 8, `dotnet restore` [audits NuGet package references for known vulnerabilities](../../tools/dotnet-restore.md#audit-for-security-vulnerabilities). In .NET 9, the default mode has changed from auditing only *direct* package references to auditing both *direct* and *transitive* package references. +Starting in .NET 8, `dotnet restore` [audits NuGet package references for known vulnerabilities](../../tools/dotnet-restore.md#audit-for-security-vulnerabilities). In .NET 9, the default mode has changed from auditing only _direct_ package references to auditing both _direct_ and _transitive_ package references. ## MSBuild script analyzers ("BuildChecks") @@ -128,7 +129,7 @@ For more information, see the [design documentation](https://github.com/dotnet/m Many users install the .NET SDK and Visual Studio at different cadences. While this flexibility is desirable, it can lead to problems for tooling that needs to interop between the two environments. One example of this kind of tooling is Roslyn Analyzers. Analyzer authors have to code for specific versions of Roslyn, but which versions are available and which is used by a given build is sometimes unclear. -This kind of version mismatch between the .NET SDK and MSBuild is referred to as a *torn SDK*. When you're in this state, you might see errors like this: +This kind of version mismatch between the .NET SDK and MSBuild is referred to as a _torn SDK_. When you're in this state, you might see errors like this: > CSC : warning CS9057: The analyzer assembly '..\dotnet\sdk\8.0.200\Sdks\Microsoft.NET.Sdk.Razor\source-generators\Microsoft.CodeAnalysis.Razor.Compiler.SourceGenerators.dll' references version '4.9.0.0' of the compiler, which is newer than the currently running version '4.8.0.0'. @@ -136,7 +137,7 @@ This kind of version mismatch between the .NET SDK and MSBuild is referred to as ## Workload sets -*Workload sets* is an SDK feature intended to give users more control over the workloads they install and the cadence of change of those workloads. In previous versions, workloads were periodically updated as new versions of individual workloads were released onto any configured NuGet feeds. Now, *all* of your workloads stay at a specific, single version until you make an explicit update gesture. +_Workload sets_ is an SDK feature intended to give users more control over the workloads they install and the cadence of change of those workloads. In previous versions, workloads were periodically updated as new versions of individual workloads were released onto any configured NuGet feeds. Now, _all_ of your workloads stay at a specific, single version until you make an explicit update gesture. You can see what mode your SDK installation is in by running `dotnet workload --info`: @@ -162,6 +163,23 @@ If you need to change back for any reason, you can run the same command with `ma For more information, see [.NET SDK workload sets](../../tools/dotnet-workload-sets.md). +## Workload history + +.NET SDK workloads are an integral part of .NET MAUI and Blazor WebAssembly. In their default configuration, you can update workloads independently as .NET tooling authors release new versions. In addition, .NET SDK installations done through Visual Studio install a parallel set of versions. Without taking care, the workload installation status of a given .NET SDK installation can drift over time, but there hasn't been a way to visualize this drift. + +To address this, .NET 9 adds a new `dotnet workload history` command to the .NET SDK. `dotnet workload history` prints out a table of the history of workload installations and modifications for the current .NET SDK installation. The table shows the date of the installation or modification, the command that was run, the workloads that were installed or modified, and the relevant versions for the command. This output can help you understand the drift in workload installations over time, and help you make informed decisions about which workloads versions to set your installation to. You can think of it as `git reflog` for workloads. + +```dotnetcli +> dotnet workload history + +Id Date Command Workloads Global.json Version Workload Version +----------------------------------------------------------------------------------------------------------------------------------------------- +1 1/1/0001 12:00:00 AM +00:00 InitialState android, ios, maccatalyst, maui-windows 9.0.100-manifests.6d3c8f5d +2 9/4/2024 8:15:33 PM -05:00 install android, aspire, ios, maccatalyst, maui-windows 9.0.100-rc.1.24453.3 +``` + +In this example, the SDK was initially installed with the `android`, `ios`, `maccatalyst`, and `maui-windows` workloads. Then, the `dotnet workload install aspire --version 9.0.100-rc.1.24453.3` command was used to install the `aspire` workload and switch to [workload sets mode](../../tools/dotnet-workload-sets.md). To return to the previous state, you can use the ID from the first column in the history table, for example, `dotnet workload update --from-history 1`. + ## Containers - [Publishing support for insecure registries](#publishing-support-for-insecure-registries) diff --git a/docs/core/whats-new/snippets/dotnet-9/csharp/Collections.cs b/docs/core/whats-new/snippets/dotnet-9/csharp/Collections.cs index ac49b9977b9fc..75769bf172996 100644 --- a/docs/core/whats-new/snippets/dotnet-9/csharp/Collections.cs +++ b/docs/core/whats-new/snippets/dotnet-9/csharp/Collections.cs @@ -62,7 +62,7 @@ private static Dictionary CountWords(ReadOnlySpan input) { Dictionary wordCounts = new(StringComparer.OrdinalIgnoreCase); Dictionary.AlternateLookup> spanLookup = - wordCounts.GetAlternateLookup>(); + wordCounts.GetAlternateLookup>(); foreach (Range wordRange in Regex.EnumerateSplits(input, @"\b\w+\b")) { diff --git a/docs/core/whats-new/snippets/dotnet-9/csharp/Compression.cs b/docs/core/whats-new/snippets/dotnet-9/csharp/Compression.cs new file mode 100644 index 0000000000000..cbaf231d1778b --- /dev/null +++ b/docs/core/whats-new/snippets/dotnet-9/csharp/Compression.cs @@ -0,0 +1,25 @@ +using System.IO; +using System.IO.Compression; + +namespace Project; +internal class Compression +{ + // + private MemoryStream CompressStream(Stream uncompressedStream) + { + MemoryStream compressorOutput = new(); + using ZLibStream compressionStream = new( + compressorOutput, + new ZLibCompressionOptions() + { + CompressionLevel = 6, + CompressionStrategy = ZLibCompressionStrategy.HuffmanOnly + } + ); + uncompressedStream.CopyTo(compressionStream); + compressionStream.Flush(); + + return compressorOutput; + } + // +} diff --git a/docs/core/whats-new/snippets/dotnet-9/csharp/Diagnostics.cs b/docs/core/whats-new/snippets/dotnet-9/csharp/Diagnostics.cs index af780d855e3b2..d6bab1b0370ab 100644 --- a/docs/core/whats-new/snippets/dotnet-9/csharp/Diagnostics.cs +++ b/docs/core/whats-new/snippets/dotnet-9/csharp/Diagnostics.cs @@ -1,5 +1,8 @@ -using System.Diagnostics; +using System; +using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.Metrics; +using System.Diagnostics.Tracing; internal class Diagnostics { @@ -14,13 +17,64 @@ public static void RunIt() // // - Meter meter = new("MeasurementLibrary.Sound"); - Gauge gauge = meter.CreateGauge( + Meter soundMeter = new("MeasurementLibrary.Sound"); + Gauge gauge = soundMeter.CreateGauge( name: "NoiseLevel", unit: "dB", // Decibels. description: "Background Noise Level" ); - gauge.Record(10, new TagList() { { "Room1", "dB" } } ); + gauge.Record(10, new TagList() { { "Room1", "dB" } }); // + + // + // The complete meter name is "MyCompany.MyMeter". + var meter = new Meter("MyCompany.MyMeter"); + // Create a counter and allow publishing values. + meter.CreateObservableCounter("MyCounter", () => 1); + + // Create the listener to use the wildcard character + // to listen to all meters using prefix names. + MyEventListener listener = new MyEventListener(); + // + } +} + +// +internal class MyEventListener : EventListener +{ + protected override void OnEventSourceCreated(EventSource eventSource) + { + Console.WriteLine(eventSource.Name); + if (eventSource.Name == "System.Diagnostics.Metrics") + { + // Listen to all meters with names starting with "MyCompany". + // If using "*", allow listening to all meters. + EnableEvents( + eventSource, + EventLevel.Informational, + (EventKeywords)0x3, + new Dictionary() { { "Metrics", "MyCompany*" } } + ); + } + } + + protected override void OnEventWritten(EventWrittenEventArgs eventData) + { + // Ignore other events. + if (eventData.EventSource.Name != "System.Diagnostics.Metrics" || + eventData.EventName == "CollectionStart" || + eventData.EventName == "CollectionStop" || + eventData.EventName == "InstrumentPublished" + ) + return; + + Console.WriteLine(eventData.EventName); + + if (eventData.Payload is not null) + { + for (int i = 0; i < eventData.Payload.Count; i++) + Console.WriteLine($"\t{eventData.PayloadNames![i]}: {eventData.Payload[i]}"); + } } } +// diff --git a/docs/core/whats-new/snippets/dotnet-9/csharp/Networking.cs b/docs/core/whats-new/snippets/dotnet-9/csharp/Networking.cs index 1e242e48baa65..3b023e4294a27 100644 --- a/docs/core/whats-new/snippets/dotnet-9/csharp/Networking.cs +++ b/docs/core/whats-new/snippets/dotnet-9/csharp/Networking.cs @@ -1,10 +1,13 @@ using System; using System.IO; +using System.Net.Http; using System.Net.ServerSentEvents; +using System.Net.WebSockets; +using System.Threading; internal class Networking { - public async static void RunIt() + public static async void RunIt() { // Stream responseStream = new MemoryStream(); @@ -13,5 +16,18 @@ public async static void RunIt() Console.WriteLine(e.Data); } // + + var uri = new Uri("http://localhost:5000"); + var httpClient = new HttpClient(); + var cancellationToken = new CancellationToken(); + + // + using var cws = new ClientWebSocket(); + cws.Options.HttpVersionPolicy = HttpVersionPolicy.RequestVersionOrHigher; + cws.Options.KeepAliveInterval = TimeSpan.FromSeconds(5); + cws.Options.KeepAliveTimeout = TimeSpan.FromSeconds(1); + + await cws.ConnectAsync(uri, httpClient, cancellationToken); + // } } diff --git a/docs/core/whats-new/snippets/dotnet-9/csharp/Program.cs b/docs/core/whats-new/snippets/dotnet-9/csharp/Program.cs index 36e7048304053..7b9921056172e 100644 --- a/docs/core/whats-new/snippets/dotnet-9/csharp/Program.cs +++ b/docs/core/whats-new/snippets/dotnet-9/csharp/Program.cs @@ -5,4 +5,5 @@ //TimeSpan.RunIt(); //Channels.RunIt(); //RegularExpressions.RunIt(); -Collections.RunIt(); +//Collections.RunIt(); +Diagnostics.RunIt(); diff --git a/docs/core/whats-new/snippets/dotnet-9/csharp/Project.csproj b/docs/core/whats-new/snippets/dotnet-9/csharp/Project.csproj index ac1ab131ad26e..a22789e316a8c 100644 --- a/docs/core/whats-new/snippets/dotnet-9/csharp/Project.csproj +++ b/docs/core/whats-new/snippets/dotnet-9/csharp/Project.csproj @@ -8,6 +8,7 @@ + diff --git a/docs/core/whats-new/snippets/dotnet-9/csharp/Runtime.cs b/docs/core/whats-new/snippets/dotnet-9/csharp/Runtime.cs index 9da000f07457b..442fcdacdbc09 100644 --- a/docs/core/whats-new/snippets/dotnet-9/csharp/Runtime.cs +++ b/docs/core/whats-new/snippets/dotnet-9/csharp/Runtime.cs @@ -53,7 +53,7 @@ static void Advance(double dt, Body[] bodies) static byte Test1() { Vector128 v = Vector128.Zero; - byte size = 1; + const byte size = 1; v = Sse2.ShiftRightLogical128BitLane(v, size); return Sse41.Extract(v, 0); } diff --git a/docs/core/whats-new/snippets/dotnet-9/csharp/Serialization.cs b/docs/core/whats-new/snippets/dotnet-9/csharp/Serialization.cs index a9a411760588b..797a528132409 100644 --- a/docs/core/whats-new/snippets/dotnet-9/csharp/Serialization.cs +++ b/docs/core/whats-new/snippets/dotnet-9/csharp/Serialization.cs @@ -95,7 +95,7 @@ public static void RunIt3() // public class Book { - public string Title { get; set; } + public required string Title { get; set; } public string? Author { get; set; } public int PublishYear { get; set; } } diff --git a/docs/core/whats-new/snippets/dotnet-9/csharp/TarEntry.cs b/docs/core/whats-new/snippets/dotnet-9/csharp/TarEntry.cs new file mode 100644 index 0000000000000..bef37338bd5c1 --- /dev/null +++ b/docs/core/whats-new/snippets/dotnet-9/csharp/TarEntry.cs @@ -0,0 +1,43 @@ +using System.Formats.Tar; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Azure.Storage.Blobs; + +namespace Project; +internal class TarEntry +{ + public static async Task RunItAsync() + { + Azure.Storage.Blobs.Models.BlobOpenReadOptions options = new(true); + CancellationToken cancellationToken = new(); + string connectionString = ""; + string blobContainerName = ""; + string blobName = ""; + + // + // Create stream for tar ball data in Azure Blob Storage. + BlobClient blobClient = new(connectionString, blobContainerName, blobName); + Stream blobClientStream = await blobClient.OpenReadAsync(options, cancellationToken); + + // Create TarReader for the stream and get a TarEntry. + TarReader tarReader = new(blobClientStream); + System.Formats.Tar.TarEntry? tarEntry = await tarReader.GetNextEntryAsync(); + + if (tarEntry is null) + return; + + // Get position of TarEntry data in blob stream. + long entryOffsetInBlobStream = tarEntry.DataOffset; + long entryLength = tarEntry.Length; + + // Create a separate stream. + Stream newBlobClientStream = await blobClient.OpenReadAsync(options, cancellationToken); + newBlobClientStream.Seek(entryOffsetInBlobStream, SeekOrigin.Begin); + + // Read tar ball content from separate BlobClient stream. + byte[] bytes = new byte[entryLength]; + await newBlobClientStream.ReadExactlyAsync(bytes, 0, (int)entryLength); + // + } +} diff --git a/docs/navigate/devops-testing/toc.yml b/docs/navigate/devops-testing/toc.yml index adb3f243913c0..714b769f477e4 100644 --- a/docs/navigate/devops-testing/toc.yml +++ b/docs/navigate/devops-testing/toc.yml @@ -497,6 +497,8 @@ items: href: ../../core/deploying/native-aot/cross-compile.md - name: Intro to AOT warnings href: ../../core/deploying/native-aot/fixing-warnings.md + - name: Intrinsic APIs marked RequiresDynamicCode + href: ../../core/deploying/native-aot/intrinsic-requiresdynamiccode-apis.md - name: AOT warnings items: - name: IL3050 diff --git a/docs/orleans/grains/grain-persistence/index.md b/docs/orleans/grains/grain-persistence/index.md index 4f2e0a483661e..c857733d83172 100644 --- a/docs/orleans/grains/grain-persistence/index.md +++ b/docs/orleans/grains/grain-persistence/index.md @@ -1,7 +1,7 @@ --- title: Grain persistence description: Learn about persistence in .NET Orleans. -ms.date: 07/03/2024 +ms.date: 09/10/2024 zone_pivot_groups: orleans-version --- @@ -208,6 +208,8 @@ var host = new HostBuilder() .Build(); ``` +[!INCLUDE [managed-identities](../../../framework/includes/managed-identities.md)] + :::zone-end Now that a storage provider has been configured with the name `"profileStore"`, we can access this provider from a grain. diff --git a/docs/orleans/host/configuration-guide/configuring-ado-dot-net-providers.md b/docs/orleans/host/configuration-guide/configuring-ado-dot-net-providers.md index bfd747825ab32..9359cc511334e 100644 --- a/docs/orleans/host/configuration-guide/configuring-ado-dot-net-providers.md +++ b/docs/orleans/host/configuration-guide/configuring-ado-dot-net-providers.md @@ -1,7 +1,7 @@ --- title: Configure ADO.NET providers description: Learn how to configure ADO.NET providers in .NET Orleans. -ms.date: 07/03/2024 +ms.date: 09/10/2024 --- # Configure ADO.NET providers @@ -60,6 +60,8 @@ siloHostBuilder.UseAdoNetClustering(options => }); ``` +[!INCLUDE [managed-identities](../../../framework/includes/managed-identities.md)] + Where the `ConnectionString` is set to a valid AdoNet Server connection string. To use ADO.NET providers for persistence, reminders, or clustering, there are scripts for creating database artifacts, to which all servers that will be hosting Orleans silos need to have access. The scripts for popular providers can be found in [ADO.NET Configuration](adonet-configuration.md). Lack of access to the target database is a typical mistake we see developers making. diff --git a/docs/orleans/implementation/streams-implementation/azure-queue-streams.md b/docs/orleans/implementation/streams-implementation/azure-queue-streams.md index 4ccd4771e6126..08c05680a555f 100644 --- a/docs/orleans/implementation/streams-implementation/azure-queue-streams.md +++ b/docs/orleans/implementation/streams-implementation/azure-queue-streams.md @@ -1,7 +1,7 @@ --- title: Azure Queue streams overview description: Explore the streaming implementation with Azure Queue in .NET Orleans. -ms.date: 07/03/2024 +ms.date: 09/10/2024 --- # Azure Queue streams overview @@ -17,7 +17,7 @@ hostBuilder configurator.ConfigureAzureQueue( ob => ob.Configure(options => { - options.ConnectionString = "xxx"; + options.ConnectionString = "[PLACEHOLDER]"; options.QueueNames = new List { "yourprefix-azurequeueprovider-0" }; })); configurator.ConfigureCacheSize(1024); @@ -28,7 +28,7 @@ hostBuilder }) // a PubSubStore could be needed, as example Azure Table Storage .AddAzureTableGrainStorage("PubSubStore", options => { - options.ConnectionString = "xxx"; + options.ConnectionString = "[PLACEHOLDER]"; }) ``` @@ -47,7 +47,7 @@ hostBuilder optionsBuilder => optionsBuilder.Configure( options => { - options.ConnectionString = "xxx"; + options.ConnectionString = "[PLACEHOLDER]"; options.QueueNames = new List { @@ -99,7 +99,7 @@ hostBuilder .AddAzureQueueStreams("AzureQueueProvider", configurator => { configurator.ConfigureAzureQueue( ob => ob.Configure(options => { - options.ConnectionString = "xxx"; + options.ConnectionString = "[PLACEHOLDER]"; options.QueueNames = new List { "yourprefix-azurequeueprovider-1", [...] diff --git a/docs/standard/io/pipelines.md b/docs/standard/io/pipelines.md index 035a6cf3e1e90..f0e531049d58a 100644 --- a/docs/standard/io/pipelines.md +++ b/docs/standard/io/pipelines.md @@ -1,5 +1,5 @@ --- -title: I/O pipelines - .NET +title: System.IO.Pipelines - .NET description: Learn how to efficiently use I/O pipelines in .NET and avoid problems in your code. ms.date: 05/09/2022 helpviewer_keywords: