diff --git a/docfx.json b/docfx.json index fe3ab9e5498de..eee0a2598e679 100644 --- a/docfx.json +++ b/docfx.json @@ -534,7 +534,8 @@ "_csharplang/proposals/csharp-11.0/*.md": "09/30/2022", "_csharplang/proposals/csharp-12.0/*.md": "08/15/2023", "_csharplang/proposals/csharp-13.0/*.md": "10/31/2024", - "_csharplang/proposals/*.md": "06/19/2025", + "_csharplang/proposals/csharp-14.0/*.md": "08/06/2025", + "_csharplang/proposals/*.md": "08/06/2025", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md": "11/08/2022", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 8.md": "11/08/2023", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md": "11/09/2024", @@ -706,15 +707,15 @@ "_csharplang/proposals/csharp-13.0/ref-struct-interfaces.md": "Allow ref struct types to implement some interfaces", "_csharplang/proposals/csharp-13.0/partial-properties.md": "All partial properties and indexers", "_csharplang/proposals/csharp-13.0/overload-resolution-priority.md": "Overload resolution priority tiebreaker attribute", - "_csharplang/proposals/field-keyword.md": "The `field` contextual keyword", - "_csharplang/proposals/unbound-generic-types-in-nameof.md": "Unbound generic types in `nameof`", - "_csharplang/proposals/first-class-span-types.md": "First-class span types", - "_csharplang/proposals/simple-lambda-parameters-with-modifiers.md": "Simple lambda parameters with modifiers", - "_csharplang/proposals/partial-events-and-constructors.md": "Partial events and constructors", - "_csharplang/proposals/null-conditional-assignment.md": "Null conditional assignment", - "_csharplang/proposals/extensions.md": "Extension members", - "_csharplang/proposals/user-defined-compound-assignment.md": "User-defined compound assignment", - "_csharplang/proposals/ignored-directives.md": "Ignored preprocessor directives", + "_csharplang/proposals/csharp-14.0/field-keyword.md": "The `field` contextual keyword", + "_csharplang/proposals/csharp-14.0/unbound-generic-types-in-nameof.md": "Unbound generic types in `nameof`", + "_csharplang/proposals/csharp-14.0/first-class-span-types.md": "First-class span types", + "_csharplang/proposals/csharp-14.0/simple-lambda-parameters-with-modifiers.md": "Simple lambda parameters with modifiers", + "_csharplang/proposals/csharp-14.0/partial-events-and-constructors.md": "Partial events and constructors", + "_csharplang/proposals/csharp-14.0/null-conditional-assignment.md": "Null conditional assignment", + "_csharplang/proposals/csharp-14.0/extensions.md": "Extension members", + "_csharplang/proposals/csharp-14.0/user-defined-compound-assignment.md": "User-defined compound assignment", + "_csharplang/proposals/csharp-14.0/ignored-directives.md": "Ignored preprocessor directives", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md": "C# compiler breaking changes since C# 10", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 8.md": "C# compiler breaking changes since C# 11", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md": "C# compiler breaking changes since C# 12", @@ -832,15 +833,15 @@ "_csharplang/proposals/csharp-13.0/ref-struct-interfaces.md": "This proposal provides features that enable interface authors to allow `ref struct` types to implement a particular interface", "_csharplang/proposals/csharp-13.0/partial-properties.md": "This proposal provides for partial properties and indexers, allowing the definition of a property or indexer to be split across multiple parts.", "_csharplang/proposals/csharp-13.0/overload-resolution-priority.md": "This proposal introduces a new attribute, `OverloadResolutionPriorityAttribute`, that can be applied to methods to influence overload resolution.", - "_csharplang/proposals/field-keyword.md": "This proposal introduces a new keyword, `field`, that accesses the compiler generated backing field in a property accessor.", - "_csharplang/proposals/unbound-generic-types-in-nameof.md": "This proposal introduces the ability to use unbound generic types such as `List<>` in `nameof` expressions. The type argument isn't required.", - "_csharplang/proposals/first-class-span-types.md": "This proposal provides several implicit conversions to `Span` and `ReadOnlySpan` that enable library authors to have fewer overloads and developers to write code that resolves to faster Span based APIs", - "_csharplang/proposals/simple-lambda-parameters-with-modifiers.md": "This proposal allows lambda parameters to be declared with modifiers without requiring their type names. You can add modifiers like `ref` and `out` to lambda parameters without specifying their type.", - "_csharplang/proposals/partial-events-and-constructors.md": "This proposal allows partial events and constructors to be declared in partial classes. The event and constructor can be split across class declarations.", - "_csharplang/proposals/null-conditional-assignment.md": "This proposal allows the null conditional operator to be used for the destination of assignment expressions. This allows you to assign a value to a property or field only if the left side is not null.", - "_csharplang/proposals/extensions.md": "This proposal enables new kinds of extension members. These new extension members support extension properties, extension static members, including extension operators.", - "_csharplang/proposals/user-defined-compound-assignment.md": "This proposal introduces user-defined compound assignment operators. Developers can override compound assignment, increment, and decrement operators.", - "_csharplang/proposals/ignored-directives.md": "This proposal allows a source file to include ignored directives. In most cases, ignored directives are used for file based programs, for example `#!`", + "_csharplang/proposals/csharp-14.0/field-keyword.md": "This proposal introduces a new keyword, `field`, that accesses the compiler generated backing field in a property accessor.", + "_csharplang/proposals/csharp-14.0/unbound-generic-types-in-nameof.md": "This proposal introduces the ability to use unbound generic types such as `List<>` in `nameof` expressions. The type argument isn't required.", + "_csharplang/proposals/csharp-14.0/first-class-span-types.md": "This proposal provides several implicit conversions to `Span` and `ReadOnlySpan` that enable library authors to have fewer overloads and developers to write code that resolves to faster Span based APIs", + "_csharplang/proposals/csharp-14.0/simple-lambda-parameters-with-modifiers.md": "This proposal allows lambda parameters to be declared with modifiers without requiring their type names. You can add modifiers like `ref` and `out` to lambda parameters without specifying their type.", + "_csharplang/proposals/csharp-14.0/partial-events-and-constructors.md": "This proposal allows partial events and constructors to be declared in partial classes. The event and constructor can be split across class declarations.", + "_csharplang/proposals/csharp-14.0/null-conditional-assignment.md": "This proposal allows the null conditional operator to be used for the destination of assignment expressions. This allows you to assign a value to a property or field only if the left side is not null.", + "_csharplang/proposals/csharp-14.0/extensions.md": "This proposal enables new kinds of extension members. These new extension members support extension properties, extension static members, including extension operators.", + "_csharplang/proposals/csharp-14.0/user-defined-compound-assignment.md": "This proposal introduces user-defined compound assignment operators. Developers can override compound assignment, increment, and decrement operators.", + "_csharplang/proposals/csharp-14.0/ignored-directives.md": "This proposal allows a source file to include ignored directives. In most cases, ignored directives are used for file based programs, for example `#!`", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md": "Learn about any breaking changes since the initial release of C# 10 and included in C# 11", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 8.md": "Learn about any breaking changes since the initial release of C# 11 and included in C# 12", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md": "Learn about any breaking changes since the initial release of C# 12 and included in C# 13", @@ -868,6 +869,7 @@ "_csharplang/proposals/csharp-11.0/*.md": "C# feature specifications", "_csharplang/proposals/csharp-12.0/*.md": "C# feature specifications", "_csharplang/proposals/csharp-13.0/*.md": "C# feature specifications", + "_csharplang/proposals/csharp-14.0/*.md": "C# feature specifications", "_csharplang/proposals/*.md": "C# feature specifications (preview)", "docs/framework/**/*.md": ".NET Framework", "docs/framework/data/adonet/**/*.md": "ADO.NET", diff --git a/docs/ai/how-to/snippets/hosted-app-auth/hosted-app-auth.csproj b/docs/ai/how-to/snippets/hosted-app-auth/hosted-app-auth.csproj index ce6055a396b5c..6946dc6a8d2a9 100644 --- a/docs/ai/how-to/snippets/hosted-app-auth/hosted-app-auth.csproj +++ b/docs/ai/how-to/snippets/hosted-app-auth/hosted-app-auth.csproj @@ -10,7 +10,7 @@ - + diff --git a/docs/ai/quickstarts/snippets/assistants/AIAssistants.csproj b/docs/ai/quickstarts/snippets/assistants/AIAssistants.csproj index 8d8e6e5cfd989..a2079d62dc1d8 100644 --- a/docs/ai/quickstarts/snippets/assistants/AIAssistants.csproj +++ b/docs/ai/quickstarts/snippets/assistants/AIAssistants.csproj @@ -10,7 +10,7 @@ - + diff --git a/docs/ai/quickstarts/snippets/evaluate-ai-responses/TestAI.csproj b/docs/ai/quickstarts/snippets/evaluate-ai-responses/TestAI.csproj index eb4a024f61ae4..858e04d4ae2a0 100644 --- a/docs/ai/quickstarts/snippets/evaluate-ai-responses/TestAI.csproj +++ b/docs/ai/quickstarts/snippets/evaluate-ai-responses/TestAI.csproj @@ -15,10 +15,10 @@ - - + + - + diff --git a/docs/ai/quickstarts/snippets/prompt-completion/azure-openai/ExtensionsAzureOpenAI.csproj b/docs/ai/quickstarts/snippets/prompt-completion/azure-openai/ExtensionsAzureOpenAI.csproj index 5ac12650e08fb..0aa3851f1b547 100644 --- a/docs/ai/quickstarts/snippets/prompt-completion/azure-openai/ExtensionsAzureOpenAI.csproj +++ b/docs/ai/quickstarts/snippets/prompt-completion/azure-openai/ExtensionsAzureOpenAI.csproj @@ -11,8 +11,8 @@ - - + + diff --git a/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.DependencyInjection/ConsoleAI.DependencyInjection.csproj b/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.DependencyInjection/ConsoleAI.DependencyInjection.csproj index dfc1a9e21bb08..14e5deb083513 100644 --- a/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.DependencyInjection/ConsoleAI.DependencyInjection.csproj +++ b/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.DependencyInjection/ConsoleAI.DependencyInjection.csproj @@ -8,7 +8,7 @@ - + diff --git a/docs/azure/migration/appmod/overview.md b/docs/azure/migration/appmod/overview.md index 515c0e1fc5d98..6fe067e8a25ad 100644 --- a/docs/azure/migration/appmod/overview.md +++ b/docs/azure/migration/appmod/overview.md @@ -45,6 +45,10 @@ When code changes are needed, the tool guides you through remediation using pred For more information, see [Predefined tasks](predefined-tasks.md). +### Upgrading .NET projects + +Upgrading .NET apps is a common task that requires substantial time and resources. GitHub Copilot App Modernization - upgrade for .NET provides an AI-based solution designed to assist with updating your .NET apps. For more information, see [GitHub Copilot App Modernization - upgrade for .NET](../../../core/porting/github-copilot-app-modernization-overview.md). + ## Common use cases App Modernization for .NET (Preview) supports the following scenarios: diff --git a/docs/core/containers/publish-configuration.md b/docs/core/containers/publish-configuration.md index ac8bf749ff2e4..235f339c4eb41 100644 --- a/docs/core/containers/publish-configuration.md +++ b/docs/core/containers/publish-configuration.md @@ -9,7 +9,7 @@ ms.date: 04/22/2025 In this reference article, you learn how to configure the container image generated when you publish a .NET app as a container. This article covers the various properties that you can set to control the image, the execution environment, and the commands that are run when the container starts. -## Configure container image +## Configure container properties You can control many aspects of the generated container through MSBuild properties. In general, if you can use a command in a _Dockerfile_ to set some configuration, you can do the same via MSBuild. @@ -18,45 +18,13 @@ You can control many aspects of the generated container through MSBuild properti There's no way of performing `RUN` commands with the .NET SDK. These commands are often used to install some OS packages or create a new OS user, or any number of arbitrary things. If you would like to keep using the .NET SDK container building feature, you can instead create a custom base image with these changes and then using this base image. For more information, see [`ContainerBaseImage`](#containerbaseimage). -### `ContainerArchiveOutputPath` - -To create a container image within a _tar.gz_ archive, use the `ContainerArchiveOutputPath` property. This feature is useful if your workflow isn't straightforward and requires that you, for example, run a scanning tool over your images before pushing them. Once the archive is created, you can move it, scan it, or load it into a local Docker toolchain. - -To publish to an archive, add the `ContainerArchiveOutputPath` property to your `dotnet publish` command, for example: - -```dotnetcli -dotnet publish \ - -p PublishProfile=DefaultContainer \ - -p ContainerArchiveOutputPath=./images/sdk-container-demo.tar.gz -``` - -You can specify either a folder name or a path with a specific file name. If you specify the folder name, the filename generated for the image archive file is named `$(ContainerRepository).tar.gz`. These archives can contain multiple tags inside them, only as single file is created for all `ContainerImageTags`. - -### Container image naming configuration - -Container images follow a specific naming convention. The name of the image is composed of several parts, the registry, optional port, repository, and optional tag and family. +## Flags that control the base image -```dockerfile -REGISTRY[:PORT]/REPOSITORY[:TAG[-FAMILY]] -``` +The following properties control which base image is used for your container and how it's selected: -For example, consider the fully qualified `mcr.microsoft.com/dotnet/runtime:8.0-alpine` image name: - -- `mcr.microsoft.com` is the registry (and in this case represents the Microsoft container registry). -- `dotnet/runtime` is the repository (but some consider this the `user/repository`). -- `8.0-alpine` is the tag and family (the family is an optional specifier that helps disambiguate OS packaging). - -Some properties described in the following sections correspond to managing parts of the generated image name. Consider the following table that maps the relationship between the image name and the build properties: - -| Image name part | MSBuild property | Example values | -| ----------------- | --------------------- | ----------------------- | -| `REGISTRY[:PORT]` | `ContainerRegistry` | `mcr.microsoft.com:443` | -| `PORT` | `ContainerPort` | `:443` | -| `REPOSITORY` | `ContainerRepository` | `dotnet/runtime` | -| `TAG` | `ContainerImageTag` | `8.0` | -| `FAMILY` | `ContainerFamily` | `-alpine` | - -The following sections describe the various properties that can be used to control the generated container image. +- [`ContainerBaseImage`](#containerbaseimage) +- [`ContainerFamily`](#containerfamily) +- [`ContainerRuntimeIdentifier(s)`](#containerruntimeidentifiers) ### `ContainerBaseImage` @@ -98,18 +66,6 @@ The preceding project configuration results in a final tag of `8.0-alpine` for a This field is free-form, and often can be used to select different operating system distributions, default package configurations, or any other _flavor_ of changes to a base image. This field is ignored when `ContainerBaseImage` is set. For more information, see [.NET container images](../docker/container-images.md). -### `ContainerPublishInParallel` - -For multi-RID containers, certain project types (like Blazor WebAssembly) may encounter build race conditions. To address this, starting with .NET SDK versions 8.0.408, 9.0.300, and 10.0, you can control the parallelism of the publish process using the `ContainerPublishInParallel` property. By default, publishing occurs in parallel for each Runtime Identifier (RID). Setting this property to `false` ensures sequential publishing, which increases stability but may take longer. - -```xml - - false - -``` - -For more information on multi-RID publishing, see [ContainerRuntimeIdentifier(s)](#containerruntimeidentifiers). - ### `ContainerRuntimeIdentifier(s)` The `ContainerRuntimeIdentifier` property specifies the OS and architecture for your container if the `ContainerBaseImage` supports multiple platforms. For example, the `mcr.microsoft.com/dotnet/runtime` image supports `linux-x64`, `linux-arm`, `linux-arm64`, and `win10-x64`. By default, this is set to the `RuntimeIdentifier` used when publishing the container. Typically, you don't need to set this property explicitly; instead, use the `-r` option with the `dotnet publish` command. If the chosen image doesn't support the specified `RuntimeIdentifier`, an error indicates the supported identifiers. @@ -131,49 +87,40 @@ To specify multiple container runtime identifiers for multi-architecture images, ``` > [!IMPORTANT] -> The `ContainerRuntimeIdentifiers` property must be a subset of the `RuntimeIdentifiers` property. If this condition isn't met, critical parts of the build pipeline may fail. +> The `ContainerRuntimeIdentifiers` property must be a subset of the `RuntimeIdentifiers` property. If this condition isn't met, critical parts of the build pipeline might fail. > > Setting multiple `ContainerRuntimeIdentifiers` results in a multi-architecture image being created. For more information, see [Multi-architecture images](#multi-architecture-images). For more information regarding the runtime identifiers supported by .NET, see [RID catalog](../rid-catalog.md). -### `ContainerRegistry` +#### Multi-architecture images -The container registry property controls the destination registry, the place that the newly created image is to be pushed to. By default it's pushed to the local Docker daemon, but you can also specify a remote registry. When using a remote registry that requires authentication, you authenticate using the well-known `docker login` mechanisms. For more information, See [authenticating to container registries](https://aka.ms/dotnet/containers/auth) for more details. For a concrete example of using this property, consider the following XML example: +Multi-architecture images enable a single container image to support multiple architectures, simplifying cross-platform development and deployment. The .NET SDK supports this through the `ContainerRuntimeIdentifiers` property. -```xml - - registry.mycorp.com:1234 - -``` +Beginning with SDK versions 8.0.405, 9.0.102, and 9.0.2xx, multi-RID container publishing is supported. When publishing with `/t:PublishContainer`: -This tooling supports publishing to any registry that supports the [Docker Registry HTTP API V2](https://distribution.github.io/distribution/spec/api/). This includes the following registries explicitly (and likely many more implicitly): +- If a single `RuntimeIdentifier` or `ContainerRuntimeIdentifier` is specified, a single-architecture container is generated as before. +- If no single `RuntimeIdentifier` is specified but multiple `RuntimeIdentifiers` or `ContainerRuntimeIdentifiers` are set, the SDK publishes the app for each specified RID and combines the resulting images into an [OCI Image Index](https://specs.opencontainers.org/image-spec/image-index/). This index allows multiple architecture-specific images to share a single name. -- [Azure Container Registry](https://azure.microsoft.com/products/container-registry) -- [Amazon Elastic Container Registry](https://aws.amazon.com/ecr/) -- [Google Artifact Registry](https://cloud.google.com/artifact-registry) -- [Docker Hub](https://hub.docker.com/) -- [GitHub Packages](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry) -- [GitLab-hosted Container Registry](https://docs.gitlab.com/ee/user/packages/container_registry/) -- [Quay.io](https://quay.io/) +> [!NOTE] +> The `ContainerRuntimeIdentifiers` property must be a subset of the `RuntimeIdentifiers` property. For more information, see [ContainerRuntimeIdentifiers](#containerruntimeidentifiers). -For notes on working with these registries, see the [registry-specific notes](https://aka.ms/dotnet/containers/auth#notes-for-specific-registries). +This feature streamlines container workflows in mixed-architecture environments. For example, a developer on a `linux-x64` host can publish a container supporting both `linux-x64` and `linux-arm64`, enabling deployment to either architecture without changing image names or labels. -### `ContainerRepository` +The generated OCI Image Index is widely supported with modern container tooling, enhancing compatibility and ease of use. -The container repository is the name of the image itself, for example, `dotnet/runtime` or `my-app`. By default, the `AssemblyName` of the project is used. +## Flags that control generated-image-independent metadata -```xml - - my-app - -``` +The following properties control metadata and configuration that applies to the generated container image regardless of the target runtime identifier: -Image names consist of one or more slash-delimited segments, each of which can only contain lowercase alphanumeric characters, periods, underscores, and dashes, and must start with a letter or number. Any other characters result in an error being thrown. +- [`ContainerImageFormat`](#containerimageformat) +- [`ContainerImageTag`](#containerimagetag) +- [`ContainerLabel`](#containerlabel) +- [`ContainerRepository`](#containerrepository) ### `ContainerImageFormat` -Starting with .NET 8.0.405, you can use the `ContainerImageFormat` MSBuild property to specify the image format as either `Docker` or `OCI`. By default, the .NET tooling infers the format from the base image. For example, .NET base images use the Docker-specific format `application/vnd.docker.distribution.manifest.v2+json`. However, many modern tools prefer the OCI format `application/vnd.oci.image.manifest.v1+json`. To force a specific format, set the property as shown: +You can use the `ContainerImageFormat` MSBuild property to specify the image format as either `Docker` or `OCI`. By default, the .NET tooling infers the format from the base image. For example, .NET base images use the Docker-specific format `application/vnd.docker.distribution.manifest.v2+json`. However, many modern tools prefer the OCI format `application/vnd.oci.image.manifest.v1+json`. To force a specific format, set the property as shown: ```xml @@ -256,96 +203,31 @@ The `ContainerLabel` node has two attributes: For a list of labels that are created by default, see [default container labels](#default-container-labels). -## Configure container execution - -To control the execution of the container, you can use the following MSBuild properties. - -### `ContainerWorkingDirectory` - -The container working directory node controls the working directory of the container, the directory that commands are executed within if not other command is run. - -By default, the `/app` directory value is used as the working directory. - -```xml - - /bin - -``` - -### `ContainerPort` - -The container port adds Transmission Control Protocol (TCP) or User Datagram Protocol (UDP) ports to the list of known ports for the container. This enables container runtimes like Docker to map these ports to the host machine automatically. This is often used as documentation for the container, but can also be used to enable automatic port mapping. - -The `ContainerPort` node has two attributes: - -- `Include`: The port number to expose. -- `Type`: Defaults to `tcp`, valid values are either `tcp` or `udp`. - -```xml - - - -``` - -Starting with .NET 8, the `ContainerPort` is inferred when not explicitly provided based on several well-known ASP.NET environment variables: - -- `ASPNETCORE_URLS` -- `ASPNETCORE_HTTP_PORTS` -- `ASPNETCORE_HTTPS_PORTS` - -If these environment variables are present, their values are parsed and converted to TCP port mappings. These environment variables are read from your base image, if present, or from the environment variables defined in your project through `ContainerEnvironmentVariable` items. For more information, see [ContainerEnvironmentVariable](#containerenvironmentvariable). - -### `ContainerEnvironmentVariable` - -The container environment variable node allows you to add environment variables to the container. Environment variables are accessible to the app running in the container immediately, and are often used to change the run-time behavior of the running app. - -The `ContainerEnvironmentVariable` node has two attributes: - -- `Include`: The name of the environment variable. -- `Value`: The value of the environment variable. - -```xml - - - -``` - -For more information, see [.NET environment variables](../tools/dotnet-environment-variables.md). - -> [!NOTE] -> It's currently not possible to set environment variables from the .NET CLI when publishing a container image. For more information, see [GitHub: .NET SDK container builds](https://github.com/dotnet/sdk-container-builds/issues/451). - -### `LocalRegistry` - -The `LocalRegistry` MSBuild property specifies the local container tooling to use when pushing to local sources. Supported values are `docker` and `podman`. If not set, the SDK determines the tool based on availability: - -- If both `docker` and `podman` exist, and `docker` is an alias for `podman`, then `podman` is used. -- If only `docker` exists, `docker` is used. -- If only `podman` exists, `podman` is used. -- If neither exists, an error is thrown. +### `ContainerRepository` -To explicitly set the local registry tool, use the following configuration: +The container repository is the name of the image itself, for example, `dotnet/runtime` or `my-app`. By default, the `AssemblyName` of the project is used. ```xml - podman + my-app ``` -## Configure container commands - -By default, the container tools launch your app using either the generated AppHost binary for your app (if your app uses an AppHost), or the `dotnet` command plus your app's DLL. - -However, you can control how your app is executed by using some combination of `ContainerAppCommand`, `ContainerAppCommandArgs`, `ContainerDefaultArgs`, and `ContainerAppCommandInstruction`. +Image names consist of one or more slash-delimited segments, each of which can only contain lowercase alphanumeric characters, periods, underscores, and dashes, and must start with a letter or number. Any other characters result in an error being thrown. -These different configuration points exist because different base images use different combinations of the container `ENTRYPOINT` and `COMMAND` properties, and you want to be able to support all of them. The defaults should be useable for most apps, but if you want to customize your app launch behavior you should: +## Flags that control execution metadata -- Identify the binary to run and set it as `ContainerAppCommand` -- Identify which arguments are _required_ for your application to run and set them as `ContainerAppCommandArgs` -- Identify which arguments (if any) are _optional_ and are able to be overridden by a user and set them as `ContainerDefaultArgs` -- Set `ContainerAppCommandInstruction` to `DefaultArgs` +The following properties control runtime-specific execution behavior and multi-architecture image generation: -For more information, see the following configuration items. +- [`ContainerAppCommand`](#containerappcommand) +- [`ContainerAppCommandArgs`](#containerappcommandargs) +- [`ContainerAppCommandInstruction`](#containerappcommandinstruction) +- [`ContainerDefaultArgs`](#containerdefaultargs) +- [`ContainerEnvironmentVariable`](#containerenvironmentvariable) +- [`ContainerPort`](#containerport) +- [`ContainerPublishInParallel`](#containerpublishinparallel) +- [`ContainerUser`](#containeruser) +- [`ContainerWorkingDirectory`](#containerworkingdirectory) ### `ContainerAppCommand` @@ -383,6 +265,24 @@ The `ContainerAppCommandArgs` configuration has a single `Include` property, whi ``` +### `ContainerAppCommandInstruction` + +The app command instruction configuration helps control the way the `ContainerEntrypoint`, `ContainerEntrypointArgs`, `ContainerAppCommand`, `ContainerAppCommandArgs`, and `ContainerDefaultArgs` are combined to form the final command that is run in the container. This depends greatly on if an `ENTRYPOINT` is present in the base image. This property takes one of three values: `"DefaultArgs"`, `"Entrypoint"`, or `"None"`. + +- `Entrypoint`: + - In this mode, the entrypoint is defined by `ContainerAppCommand`, `ContainerAppCommandArgs`, and `ContainerDefaultArgs`. +- `None`: + - In this mode, the entrypoint is defined by `ContainerEntrypoint`, `ContainerEntrypointArgs`, and `ContainerDefaultArgs`. +- `DefaultArgs`: + - This is the most complex mode—if none of the `ContainerEntrypoint[Args]` items are present, the `ContainerAppCommand[Args]` and `ContainerDefaultArgs` are used to create the entrypoint and command. The base image entrypoint for base images that have it hard-coded to `dotnet` or `/usr/bin/dotnet` is skipped so that you have complete control. + - If both `ContainerEntrypoint` and `ContainerAppCommand` are present, then `ContainerEntrypoint` becomes the entrypoint, and `ContainerAppCommand` becomes the command. + +> [!NOTE] +> The `ContainerEntrypoint` and `ContainerEntrypointArgs` configuration items are deprecated as of .NET 8. + +> [!IMPORTANT] +> This is for advanced users-most apps shouldn't need to customize their entrypoint to this degree. For more information and if you'd like to provide use cases for your scenarios, see [GitHub: .NET SDK container builds discussions](https://github.com/dotnet/sdk-container-builds/discussions). + ### `ContainerDefaultArgs` This default args configuration item represents any user-overridable arguments for your app. This is a good way to provide defaults that your app might need to run in a way that makes it easy to start, yet still easy to customize. @@ -402,23 +302,60 @@ The `ContainerDefaultArgs` configuration has a single `Include` property, which ``` -### `ContainerAppCommandInstruction` +### `ContainerEnvironmentVariable` -The app command instruction configuration helps control the way the `ContainerEntrypoint`, `ContainerEntrypointArgs`, `ContainerAppCommand`, `ContainerAppCommandArgs`, and `ContainerDefaultArgs` are combined to form the final command that is run in the container. This depends greatly on if an `ENTRYPOINT` is present in the base image. This property takes one of three values: `"DefaultArgs"`, `"Entrypoint"`, or `"None"`. +The container environment variable node allows you to add environment variables to the container. Environment variables are accessible to the app running in the container immediately, and are often used to change the run-time behavior of the running app. -- `Entrypoint`: - - In this mode, the entrypoint is defined by `ContainerAppCommand`, `ContainerAppCommandArgs`, and `ContainerDefaultArgs`. -- `None`: - - In this mode, the entrypoint is defined by `ContainerEntrypoint`, `ContainerEntrypointArgs`, and `ContainerDefaultArgs`. -- `DefaultArgs`: - - This is the most complex mode—if none of the `ContainerEntrypoint[Args]` items are present, the `ContainerAppCommand[Args]` and `ContainerDefaultArgs` are used to create the entrypoint and command. The base image entrypoint for base images that have it hard-coded to `dotnet` or `/usr/bin/dotnet` is skipped so that you have complete control. - - If both `ContainerEntrypoint` and `ContainerAppCommand` are present, then `ContainerEntrypoint` becomes the entrypoint, and `ContainerAppCommand` becomes the command. +The `ContainerEnvironmentVariable` node has two attributes: + +- `Include`: The name of the environment variable. +- `Value`: The value of the environment variable. + +```xml + + + +``` + +For more information, see [.NET environment variables](../tools/dotnet-environment-variables.md). > [!NOTE] -> The `ContainerEntrypoint` and `ContainerEntrypointArgs` configuration items are deprecated as of .NET 8. +> It's currently not possible to set environment variables from the .NET CLI when publishing a container image. For more information, see [GitHub: .NET SDK container builds](https://github.com/dotnet/sdk-container-builds/issues/451). -> [!IMPORTANT] -> This is for advanced users-most apps shouldn't need to customize their entrypoint to this degree. For more information and if you'd like to provide use cases for your scenarios, see [GitHub: .NET SDK container builds discussions](https://github.com/dotnet/sdk-container-builds/discussions). +### `ContainerPort` + +The container port adds Transmission Control Protocol (TCP) or User Datagram Protocol (UDP) ports to the list of known ports for the container. This enables container runtimes like Docker to map these ports to the host machine automatically. This is often used as documentation for the container, but can also be used to enable automatic port mapping. + +The `ContainerPort` node has two attributes: + +- `Include`: The port number to expose. +- `Type`: Defaults to `tcp`, valid values are either `tcp` or `udp`. + +```xml + + + +``` + +Starting with .NET 8, the `ContainerPort` is inferred when not explicitly provided based on several well-known ASP.NET environment variables: + +- `ASPNETCORE_URLS` +- `ASPNETCORE_HTTP_PORTS` +- `ASPNETCORE_HTTPS_PORTS` + +If these environment variables are present, their values are parsed and converted to TCP port mappings. These environment variables are read from your base image, if present, or from the environment variables defined in your project through `ContainerEnvironmentVariable` items. For more information, see [ContainerEnvironmentVariable](#containerenvironmentvariable). + +### `ContainerPublishInParallel` + +For multi-RID containers, certain project types (like Blazor WebAssembly) might encounter build race conditions. To address this, starting with .NET SDK versions 8.0.408, 9.0.300, and 10.0, you can control the parallelism of the publish process using the `ContainerPublishInParallel` property. By default, publishing occurs in parallel for each Runtime Identifier (RID). Setting this property to `false` ensures sequential publishing, which increases stability but might take longer. + +```xml + + false + +``` + +For more information on multi-RID publishing, see [ContainerRuntimeIdentifier(s)](#containerruntimeidentifiers). ### `ContainerUser` @@ -458,43 +395,124 @@ Alternatively, you can set this value when calling `dotnet publish` from the com dotnet publish -p ContainerUser=root ``` -### Default container labels +### `ContainerWorkingDirectory` -Labels are often used to provide consistent metadata on container images. The built-in container tools provide some default labels to increase the quality of the generated images. All default label generation can be disabled by setting `ContainerGenerateLabels` to `false`. In addition, each default label has an individual enablement flag that can be set to `false` to disable that specific label. +The container working directory node controls the working directory of the container, the directory that commands are executed within if not other command is run. -Where possible, existing MSBuild properties provide the values for these labels. Other properties allow for explicit control of their values. +By default, the `/app` directory value is used as the working directory. -| Annotation | Default Value | Dedicated Property Name | Fallback Property Name | Enabled Property Name | Notes | -| ------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------- | ---------------------------- | -------------------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | -| `org.opencontainers.image.created` and `org.opencontainers.artifact.created` | The [RFC 3339](https://tools.ietf.org/html/rfc3339#section-5.6) format of the current UTC DateTime | | | `ContainerGenerateLabelsImageCreated` | | -| `org.opencontainers.artifact.description` and `org.opencontainers.image.description` | | `ContainerDescription` | `Description` | `ContainerGenerateLabelsImageDescription` | | -| `org.opencontainers.image.authors` | | `ContainerAuthors` | `Authors` | `ContainerGenerateLabelsImageAuthors` | | -| `org.opencontainers.image.url` | | `ContainerInformationUrl` | `PackageProjectUrl` | `ContainerGenerateLabelsImageUrl` | | -| `org.opencontainers.image.documentation` | | `ContainerDocumentationUrl` | `PackageProjectUrl` | `ContainerGenerateLabelsImageDocumentation` | | -| `org.opencontainers.image.version` | | `ContainerVersion` | `PackageVersion` | `ContainerGenerateLabelsImageVersion` | | -| `org.opencontainers.image.vendor` | | `ContainerVendor` | | `ContainerGenerateLabelsImageVendor` | | -| `org.opencontainers.image.licenses` | | `ContainerLicenseExpression` | `PackageLicenseExpression` | `ContainerGenerateLabelsImageLicenses` | | -| `org.opencontainers.image.title` | | `ContainerTitle` | `Title` | `ContainerGenerateLabelsImageTitle` | | -| `org.opencontainers.image.base.name` | | `ContainerBaseImage` | | `ContainerGenerateLabelsImageBaseName` | | -| `org.opencontainers.image.base.digest` | | | | `ContainerGenerateLabelsImageBaseDigest` | This is the SHA digest of the chosen base image. Available from .NET SDK 9.0.100 onwards. | -| `org.opencontainers.image.source` | | `PrivateRepositoryUrl` | | `ContainerGenerateLabelsImageSource` | Only written if `PublishRepositoryUrl` is `true`. Also relies on Sourcelink infrastructure being part of the build. | -| `org.opencontainers.image.revision` | | `SourceRevisionId` | | `ContainerGenerateLabelsImageRevision` | Only written if `PublishRepositoryUrl` is `true`. Also relies on Sourcelink infrastructure being part of the build. | - -## Multi-architecture images +```xml + + /bin + +``` -Multi-architecture images enable a single container image to support multiple architectures, simplifying cross-platform development and deployment. The .NET SDK supports this through the `ContainerRuntimeIdentifiers` property. +## Flags that control the destination of the generated image -Beginning with SDK versions 8.0.405, 9.0.102, and 9.0.2xx, multi-RID container publishing is supported. When publishing with `/t:PublishContainer`: +The following properties control where the generated container image is stored or published: -- If a single `RuntimeIdentifier` or `ContainerRuntimeIdentifier` is specified, a single-architecture container is generated as before. -- If no single `RuntimeIdentifier` is specified but multiple `RuntimeIdentifiers` or `ContainerRuntimeIdentifiers` are set, the SDK publishes the app for each specified RID and combines the resulting images into an [OCI Image Index](https://specs.opencontainers.org/image-spec/image-index/). This index allows multiple architecture-specific images to share a single name. +- [`ContainerArchiveOutputPath`](#containerarchiveoutputpath) +- [`ContainerRegistry`](#containerregistry) +- [`LocalRegistry`](#localregistry) -> [!NOTE] -> The `ContainerRuntimeIdentifiers` property must be a subset of the `RuntimeIdentifiers` property. For more information, see [ContainerRuntimeIdentifiers](#containerruntimeidentifiers). +### `ContainerArchiveOutputPath` -This feature streamlines container workflows in mixed-architecture environments. For example, a developer on a `linux-x64` host can publish a container supporting both `linux-x64` and `linux-arm64`, enabling deployment to either architecture without changing image names or labels. +To create a container image within a _tar.gz_ archive, use the `ContainerArchiveOutputPath` property. This feature is useful if your workflow isn't straightforward and requires that you, for example, run a scanning tool over your images before pushing them. Once the archive is created, you can move it, scan it, or load it into a local Docker toolchain. -The generated OCI Image Index is widely supported with modern container tooling, enhancing compatibility and ease of use. +To publish to an archive, add the `ContainerArchiveOutputPath` property to your `dotnet publish` command, for example: + +```dotnetcli +dotnet publish \ + -p PublishProfile=DefaultContainer \ + -p ContainerArchiveOutputPath=./images/sdk-container-demo.tar.gz +``` + +You can specify either a folder name or a path with a specific file name. If you specify the folder name, the filename generated for the image archive file is named `$(ContainerRepository).tar.gz`. These archives can contain multiple tags inside them, only as single file is created for all `ContainerImageTags`. + +### `ContainerRegistry` + +The container registry property controls the destination registry, the place that the newly created image is to be pushed to. By default it's pushed to the local Docker daemon, but you can also specify a remote registry. When using a remote registry that requires authentication, you authenticate using the well-known `docker login` mechanisms. For more information, See [authenticating to container registries](https://aka.ms/dotnet/containers/auth) for more details. For a concrete example of using this property, consider the following XML example: + +```xml + + registry.mycorp.com:1234 + +``` + +This tooling supports publishing to any registry that supports the [Docker Registry HTTP API V2](https://distribution.github.io/distribution/spec/api/). This includes the following registries explicitly (and likely many more implicitly): + +- [Azure Container Registry](https://azure.microsoft.com/products/container-registry) +- [Amazon Elastic Container Registry](https://aws.amazon.com/ecr/) +- [Google Artifact Registry](https://cloud.google.com/artifact-registry) +- [Docker Hub](https://hub.docker.com/) +- [GitHub Packages](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry) +- [GitLab-hosted Container Registry](https://docs.gitlab.com/ee/user/packages/container_registry/) +- [Quay.io](https://quay.io/) + +For notes on working with these registries, see the [registry-specific notes](https://aka.ms/dotnet/containers/auth#notes-for-specific-registries). + +### `LocalRegistry` + +The `LocalRegistry` MSBuild property specifies the local container tooling to use when pushing to local sources. Supported values are `docker` and `podman`. If not set, the SDK determines the tool based on availability: + +- If both `docker` and `podman` exist, and `docker` is an alias for `podman`, then `podman` is used. +- If only `docker` exists, `docker` is used. +- If only `podman` exists, `podman` is used. +- If neither exists, an error is thrown. + +To explicitly set the local registry tool, use the following configuration: + +```xml + + podman + +``` + +## Container image naming configuration + +Container images follow a specific naming convention. The name of the image is composed of several parts, the registry, optional port, repository, and optional tag and family. + +```dockerfile +REGISTRY[:PORT]/REPOSITORY[:TAG[-FAMILY]] +``` + +For example, consider the fully qualified `mcr.microsoft.com/dotnet/runtime:8.0-alpine` image name: + +- `mcr.microsoft.com` is the registry (and in this case represents the Microsoft container registry). +- `dotnet/runtime` is the repository (but some consider this the `user/repository`). +- `8.0-alpine` is the tag and family (the family is an optional specifier that helps disambiguate OS packaging). + +Some properties described in the following sections correspond to managing parts of the generated image name. Consider the following table that maps the relationship between the image name and the build properties: + +| Image name part | MSBuild property | Example values | +|-------------------|-----------------------------------------------|-------------------------| +| `REGISTRY[:PORT]` | [`ContainerRegistry`](#containerregistry) | `mcr.microsoft.com:443` | +| `PORT` | [`ContainerPort`](#containerport) | `:443` | +| `REPOSITORY` | [`ContainerRepository`](#containerrepository) | `dotnet/runtime` | +| `TAG` | [`ContainerImageTag`](#containerimagetag) | `8.0` | +| `FAMILY` | [`ContainerFamily`](#containerfamily) | `-alpine` | + +## Default container labels + +Labels are often used to provide consistent metadata on container images. The built-in container tools provide some default labels to increase the quality of the generated images. All default label generation can be disabled by setting `ContainerGenerateLabels` to `false`. In addition, each default label has an individual enablement flag that can be set to `false` to disable that specific label. + +Where possible, existing MSBuild properties provide the values for these labels. Other properties allow for explicit control of their values. + +| Annotation | Default value | Dedicated property name | Fallback property name | Enabled property name | Notes | +|------------|---------------|-------------------------|------------------------|-----------------------|-------| +| `org.opencontainers.image.created` and `org.opencontainers.artifact.created` | The [RFC 3339](https://tools.ietf.org/html/rfc3339#section-5.6) format of the current UTC DateTime | | | `ContainerGenerateLabelsImageCreated` | | +| `org.opencontainers.artifact.description` and `org.opencontainers.image.description` | | `ContainerDescription` | `Description` | `ContainerGenerateLabelsImageDescription` | | +| `org.opencontainers.image.authors` | | `ContainerAuthors` | `Authors` | `ContainerGenerateLabelsImageAuthors` | | +| `org.opencontainers.image.url` | | `ContainerInformationUrl` | `PackageProjectUrl` | `ContainerGenerateLabelsImageUrl` | | +| `org.opencontainers.image.documentation` | | `ContainerDocumentationUrl` | `PackageProjectUrl` | `ContainerGenerateLabelsImageDocumentation` | | +| `org.opencontainers.image.version` | | `ContainerVersion` | `PackageVersion` | `ContainerGenerateLabelsImageVersion` | | +| `org.opencontainers.image.vendor` | | `ContainerVendor` | | `ContainerGenerateLabelsImageVendor` | | +| `org.opencontainers.image.licenses` | | `ContainerLicenseExpression` | `PackageLicenseExpression` | `ContainerGenerateLabelsImageLicenses` | | +| `org.opencontainers.image.title` | | `ContainerTitle` | `Title` | `ContainerGenerateLabelsImageTitle` | | +| `org.opencontainers.image.base.name` | | `ContainerBaseImage` | |`ContainerGenerateLabelsImageBaseName` | | +| `org.opencontainers.image.base.digest` | | | | `ContainerGenerateLabelsImageBaseDigest` | This is the SHA digest of the chosen base image. Available from .NET SDK 9.0.100 onwards. | +| `org.opencontainers.image.source` | | `PrivateRepositoryUrl` | | `ContainerGenerateLabelsImageSource` | Only written if `PublishRepositoryUrl` is `true`. Also relies on Sourcelink infrastructure being part of the build. | +| `org.opencontainers.image.revision` | | `SourceRevisionId` | | `ContainerGenerateLabelsImageRevision` | Only written if `PublishRepositoryUrl` is `true`. Also relies on Sourcelink infrastructure being part of the build. | ## See also diff --git a/docs/core/containers/snippets/Worker/DotNet.ContainerImage.csproj b/docs/core/containers/snippets/Worker/DotNet.ContainerImage.csproj index 0d41c4d38ee35..09e221740c3b6 100644 --- a/docs/core/containers/snippets/Worker/DotNet.ContainerImage.csproj +++ b/docs/core/containers/snippets/Worker/DotNet.ContainerImage.csproj @@ -9,6 +9,6 @@ - + diff --git a/docs/core/diagnostics/snippets/resource-monitoring/resource-monitoring.csproj b/docs/core/diagnostics/snippets/resource-monitoring/resource-monitoring.csproj index 2e0f6f0a3c345..9ab66eac0a67b 100644 --- a/docs/core/diagnostics/snippets/resource-monitoring/resource-monitoring.csproj +++ b/docs/core/diagnostics/snippets/resource-monitoring/resource-monitoring.csproj @@ -8,10 +8,10 @@ - - + + - + diff --git a/docs/core/extensions/snippets/configuration/app-lifetime/app-lifetime.csproj b/docs/core/extensions/snippets/configuration/app-lifetime/app-lifetime.csproj index b8ccd8f528dab..b86e1dae56410 100644 --- a/docs/core/extensions/snippets/configuration/app-lifetime/app-lifetime.csproj +++ b/docs/core/extensions/snippets/configuration/app-lifetime/app-lifetime.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/docs/core/extensions/snippets/configuration/console-basic-builder/console-basic-builder.csproj b/docs/core/extensions/snippets/configuration/console-basic-builder/console-basic-builder.csproj index 4f135363a9f01..8c6977887019a 100644 --- a/docs/core/extensions/snippets/configuration/console-basic-builder/console-basic-builder.csproj +++ b/docs/core/extensions/snippets/configuration/console-basic-builder/console-basic-builder.csproj @@ -9,7 +9,7 @@ - + diff --git a/docs/core/extensions/snippets/configuration/console-binder-gen/console-binder-gen.csproj b/docs/core/extensions/snippets/configuration/console-binder-gen/console-binder-gen.csproj index 3d38cee9a48eb..64d7753cf658a 100644 --- a/docs/core/extensions/snippets/configuration/console-binder-gen/console-binder-gen.csproj +++ b/docs/core/extensions/snippets/configuration/console-binder-gen/console-binder-gen.csproj @@ -13,10 +13,10 @@ - - - - + + + + diff --git a/docs/core/extensions/snippets/configuration/console-validation-gen/console-validation-gen.csproj b/docs/core/extensions/snippets/configuration/console-validation-gen/console-validation-gen.csproj index 66be5e1ffb0a1..3c72c8bf089c6 100644 --- a/docs/core/extensions/snippets/configuration/console-validation-gen/console-validation-gen.csproj +++ b/docs/core/extensions/snippets/configuration/console-validation-gen/console-validation-gen.csproj @@ -19,10 +19,10 @@ - - - - + + + + diff --git a/docs/core/extensions/snippets/configuration/custom-provider/custom-provider.csproj b/docs/core/extensions/snippets/configuration/custom-provider/custom-provider.csproj index bbd8d2d130fe8..6f4bde357432f 100644 --- a/docs/core/extensions/snippets/configuration/custom-provider/custom-provider.csproj +++ b/docs/core/extensions/snippets/configuration/custom-provider/custom-provider.csproj @@ -9,11 +9,11 @@ - - - - - + + + + + diff --git a/docs/core/extensions/snippets/configuration/options-noparams/options-noparams.csproj b/docs/core/extensions/snippets/configuration/options-noparams/options-noparams.csproj index 38fc8756fa5e5..cc2d029decbce 100644 --- a/docs/core/extensions/snippets/configuration/options-noparams/options-noparams.csproj +++ b/docs/core/extensions/snippets/configuration/options-noparams/options-noparams.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/docs/core/extensions/snippets/http/typed/typed.csproj b/docs/core/extensions/snippets/http/typed/typed.csproj index b04722b6465d1..ec27e8aa6e22c 100644 --- a/docs/core/extensions/snippets/http/typed/typed.csproj +++ b/docs/core/extensions/snippets/http/typed/typed.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/docs/core/extensions/snippets/primitives/change/tokens.csproj b/docs/core/extensions/snippets/primitives/change/tokens.csproj index 42eea7e02fe75..b6da3118d8537 100644 --- a/docs/core/extensions/snippets/primitives/change/tokens.csproj +++ b/docs/core/extensions/snippets/primitives/change/tokens.csproj @@ -9,7 +9,7 @@ - + diff --git a/docs/core/extensions/snippets/workers/windows-service/App.WindowsService.csproj b/docs/core/extensions/snippets/workers/windows-service/App.WindowsService.csproj index cc74b4b53d95b..0d03067e7a0e6 100644 --- a/docs/core/extensions/snippets/workers/windows-service/App.WindowsService.csproj +++ b/docs/core/extensions/snippets/workers/windows-service/App.WindowsService.csproj @@ -12,7 +12,7 @@ - - + + diff --git a/docs/core/testing/mstest-analyzers/mstest0045.md b/docs/core/testing/mstest-analyzers/mstest0045.md index 2f9bfb024cee8..bb42d89bb9635 100644 --- a/docs/core/testing/mstest-analyzers/mstest0045.md +++ b/docs/core/testing/mstest-analyzers/mstest0045.md @@ -30,6 +30,11 @@ A test method uses , you should set `CooperativeCancellation` to `true` to enable cooperative cancellation. Without cooperative cancellation, the test framework stops observing the test execution when the timeout is reached, but the test continues running in the background. This can lead to problems for other tests or cleanup steps, as the original test is still executing and might interfere with subsequent operations. When using cooperative cancellation mode, MSTest only triggers cancellation of the token and you're responsible for flowing and utilizing the test context token in your test code. This mode aligns with the default behavior of cancellation in .NET. @@ -38,6 +43,21 @@ When using cooperative cancellation mode, MSTest only triggers cancellation of t Use the provided code fixer to automatically set the `CooperativeCancellation` property to `true` on the . You can also manually add the property if needed. +```csharp +[TestClass] +public class TestClass1 +{ + public TestContext TestContext { get; set; } + + [Timeout(TimeoutValue, CooperativeCancellation = true)] + [TestMethod] + public void TestMethod1() + { + // Respect TestContext.CancellationTokenSource.Token + } +} +``` + Alternatively, you can configure cooperative cancellation globally in your [runsettings](/dotnet/core/testing/unit-testing-mstest-configure#mstest-element) or [testconfig.json](/dotnet/core/testing/unit-testing-mstest-configure#timeout-settings) file to apply this setting to all timeout attributes in your test project. ## When to suppress warnings diff --git a/docs/core/tools/dotnet-install-script.md b/docs/core/tools/dotnet-install-script.md index 1800e8061ad5a..679b112723678 100644 --- a/docs/core/tools/dotnet-install-script.md +++ b/docs/core/tools/dotnet-install-script.md @@ -288,6 +288,48 @@ The install scripts do not update the registry on Windows. They just download th curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin ``` +- Install multiple versions while not overwriting `dotnet` binaries from prior installs. + + If you install .NET SDKs or the .NET runtime from an earlier version on top of a newer version, you need to use `--skip-non-versioned-files` so that + the 'unversioned' `dotnet` files from the earlier version don't overwrite the same files from the newer version. + + ```shell + :~ $ ./dotnet-install.sh --channel 9.0 --install-dir local-dotnet # installs the latest 9 SDK to the specified directory + dotnet-install: Attempting to download using aka.ms link https://builds.dotnet.microsoft.com/dotnet/Sdk/9.0.303/dotnet-sdk-9.0.303-linux-x64.tar.gz + dotnet-install: Remote file https://builds.dotnet.microsoft.com/dotnet/Sdk/9.0.303/dotnet-sdk-9.0.303-linux-x64.tar.gz size is 218004272 bytes. + dotnet-install: Extracting archive from https://builds.dotnet.microsoft.com/dotnet/Sdk/9.0.303/dotnet-sdk-9.0.303-linux-x64.tar.gz + dotnet-install: Downloaded file size is 218004272 bytes. + dotnet-install: The remote and local file sizes are equal. + dotnet-install: Installed version is 9.0.303 + dotnet-install: Adding to current process PATH: `$HOME/local-dotnet`. Note: This change will be visible only when sourcing script. + dotnet-install: Note that the script does not resolve dependencies during installation. + dotnet-install: To check the list of dependencies, go to https://learn.microsoft.com/dotnet/core/install, select your operating system and check the "Dependencies" section. + dotnet-install: Installation finished successfully. + :~ $ ./local-dotnet/dotnet --list-runtimes # see what runtimes we have available + Microsoft.AspNetCore.App 9.0.7 [$HOME/local-dotnet/shared/Microsoft.AspNetCore.App] + Microsoft.NETCore.App 9.0.7 [$HOME/local-dotnet/shared/Microsoft.NETCore.App] + :~ $ ./local-dotnet/dotnet --list-sdks # see what SDKs we have available + 9.0.303 [$HOME/local-dotnet/sdk] + :~ $ ./dotnet-install.sh --channel 8.0 --install-dir local-dotnet --skip-non-versioned-files # install the 8 SDK to the same place, but keep the 9 dotnet binaries + dotnet-install: Attempting to download using aka.ms link https://builds.dotnet.microsoft.com/dotnet/Sdk/8.0.412/dotnet-sdk-8.0.412-linux-x64.tar.gz + dotnet-install: Remote file https://builds.dotnet.microsoft.com/dotnet/Sdk/8.0.412/dotnet-sdk-8.0.412-linux-x64.tar.gz size is 216096947 bytes. + dotnet-install: Extracting archive from https://builds.dotnet.microsoft.com/dotnet/Sdk/8.0.412/dotnet-sdk-8.0.412-linux-x64.tar.gz + dotnet-install: Downloaded file size is 216096947 bytes. + dotnet-install: The remote and local file sizes are equal. + dotnet-install: Installed version is 8.0.412 + dotnet-install: Adding to current process PATH: `$HOME/local-dotnet`. Note: This change will be visible only when sourcing script. + dotnet-install: Note that the script does not resolve dependencies during installation. + dotnet-install: To check the list of dependencies, go to https://learn.microsoft.com/dotnet/core/install, select your operating system and check the "Dependencies" section. + dotnet-install: Installation finished successfully. + :~ $ ./local-dotnet/dotnet --list-runtimes # we should have 8 and 9 Runtimes now + Microsoft.AspNetCore.App 8.0.18 [$HOME/local-dotnet/shared/Microsoft.AspNetCore.App] + Microsoft.AspNetCore.App 9.0.7 [$HOME/local-dotnet/shared/Microsoft.AspNetCore.App] + Microsoft.NETCore.App 8.0.18 [$HOME/local-dotnet/shared/Microsoft.NETCore.App] + Microsoft.NETCore.App 9.0.7 [$HOME/local-dotnet/shared/Microsoft.NETCore.App] + :~ $ ./local-dotnet/dotnet --list-sdks # we should have 2 SDKs now + 8.0.412 [$HOME/local-dotnet/sdk] + 9.0.303 [$HOME/local-dotnet/sdk] + ## Set environment variables Manually installing .NET doesn't add the environment variables system-wide, and generally only works for the session in which .NET was installed. There are two environment variables you should set for your operating system: diff --git a/docs/core/tools/dotnet-nuget-push.md b/docs/core/tools/dotnet-nuget-push.md index 3405c8b0adbfe..f261e6f246b99 100644 --- a/docs/core/tools/dotnet-nuget-push.md +++ b/docs/core/tools/dotnet-nuget-push.md @@ -15,7 +15,7 @@ ms.date: 02/14/2020 ## Synopsis ```dotnetcli -dotnet nuget push [] [-d|--disable-buffering] [--force-english-output] +dotnet nuget push [] [--allow-insecure-connections] [-d|--disable-buffering] [--force-english-output] [--interactive] [-k|--api-key ] [-n|--no-symbols] [--no-service-endpoint] [-s|--source ] [--skip-duplicate] [-sk|--symbol-api-key ] [-ss|--symbol-source ] @@ -50,6 +50,10 @@ Alternatively, use the NuGet CLI for the first package, then you can use `dotnet ## Options +- **`--allow-insecure-connections`** + + Allows pushing to HTTP sources (insecure). + - **`-d|--disable-buffering`** Disables buffering when pushing to an HTTP(S) server to reduce memory usage. diff --git a/docs/core/tools/dotnet-tool-install.md b/docs/core/tools/dotnet-tool-install.md index 7aba847853310..d8ea2002dba2d 100644 --- a/docs/core/tools/dotnet-tool-install.md +++ b/docs/core/tools/dotnet-tool-install.md @@ -50,6 +50,9 @@ The `dotnet tool install` command provides a way for you to install .NET tools o * To install a global tool in a custom location, use the `--tool-path` option. * To install a local tool, omit the `--global` and `--tool-path` options. +> [!WARNING] +> Make sure the directory you specify with the `--tool-path` option is secure. Tools installed in this location can be executed directly, so using an untrusted or shared path might introduce security risks. + ## Installation locations ### Global tools @@ -121,6 +124,11 @@ For more information, see [Install a local tool](global-tools.md#install-a-local For more information on how manifests are located, see [Install a local tool](global-tools.md#install-a-local-tool). + Starting in .NET 10, this flag is applied automatically if no tools manifest is found. + + > [!WARNING] + > Don't run tool commands from the **Downloads** folder or any shared location. The CLI walks up the directory tree to find a tool manifest, which might cause it to use a manifest you don't expect. Always run tool commands from a trusted, project-specific directory. + - **`--disable-parallel`** Prevent restoring multiple projects in parallel. diff --git a/docs/core/tools/dotnet.md b/docs/core/tools/dotnet.md index 4766e7e51320e..03cfa024da649 100644 --- a/docs/core/tools/dotnet.md +++ b/docs/core/tools/dotnet.md @@ -195,7 +195,7 @@ The following options are available only when `dotnet` runs an application by us | Command | Function | |---------------------------------------------------|-------------------------------| | [dotnet package add](dotnet-package-add.md) | Adds a NuGet package. | -| [dotnet package list](dotnet-package-add.md) | Lists NuGet packages. | +| [dotnet package list](dotnet-package-list.md) | Lists NuGet packages. | | [dotnet package remove](dotnet-package-remove.md) | Removes a NuGet package. | | [dotnet package search](dotnet-package-search.md) | Searches for a NuGet package. | diff --git a/docs/core/tools/global-tools-how-to-create.md b/docs/core/tools/global-tools-how-to-create.md index e1f69e8e8e623..5b01fc341b93e 100644 --- a/docs/core/tools/global-tools-how-to-create.md +++ b/docs/core/tools/global-tools-how-to-create.md @@ -177,6 +177,9 @@ Before you can pack and distribute the application as a tool, you need to modify `` is an optional element that specifies the command that will invoke the tool after it's installed. If this element isn't provided, the command name for the tool is the assembly name, which is typically the project file name without the *.csproj* extension. + > [!NOTE] + > Choose a unique value for ``. Avoid using file extensions (like `.exe` or `.cmd`) because the tool is installed as an app host and the command should not include an extension. This helps prevent conflicts with existing commands and ensures a smooth installation experience. + `` is an optional element that determines where the NuGet package will be produced. The NuGet package is what the .NET CLI uses to install your tool. The project file now looks like the following example: diff --git a/docs/core/tools/global-tools.md b/docs/core/tools/global-tools.md index 611a54c1195bb..1fdcfafa9989d 100644 --- a/docs/core/tools/global-tools.md +++ b/docs/core/tools/global-tools.md @@ -108,6 +108,9 @@ dotnet new tool-manifest This command creates a manifest file named *dotnet-tools.json* under the *.config* directory. To add a local tool to the manifest file, use the [dotnet tool install](dotnet-tool-install.md) command and **omit** the `--global` and `--tool-path` options, as shown in the following example: +> [!WARNING] +> Make sure the tool manifest file is stored in a controlled location. The .NET CLI launches local tools with `dotnet tool run` based on the contents of the tool manifest. If the manifest is modified by an untrusted party, it could cause the CLI to run malicious code. + ```dotnetcli dotnet tool install dotnetsay ``` diff --git a/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTest/StringLibraryTest.csproj b/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTest/StringLibraryTest.csproj index 6456f33572ef0..91326d2826074 100644 --- a/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTest/StringLibraryTest.csproj +++ b/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTest/StringLibraryTest.csproj @@ -7,7 +7,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/docs/csharp/asynchronous-programming/async-scenarios.md b/docs/csharp/asynchronous-programming/async-scenarios.md index 7246ade88a18b..e72592944ddfc 100644 --- a/docs/csharp/asynchronous-programming/async-scenarios.md +++ b/docs/csharp/asynchronous-programming/async-scenarios.md @@ -130,7 +130,27 @@ You can write this code more succinctly by using LINQ: :::code language="csharp" source="snippets/async-scenarios/Program.cs" ID="GetUsersForDatasetByLINQ"::: -Although you write less code by using LINQ, exercise caution when mixing LINQ with asynchronous code. LINQ uses deferred (or lazy) execution. Asynchronous calls don't happen immediately as they do in a `foreach` loop, unless you force the generated sequence to iterate with a call to the `.ToList()` or `.ToArray()` method. This example uses the method to perform the query eagerly and store the results in an array. This approach forces the `id => GetUserAsync(id)` statement to run and initiate the task. +Although you write less code by using LINQ, exercise caution when mixing LINQ with asynchronous code. LINQ uses deferred (or lazy) execution, which means that without immediate evaluation, async calls don't happen until the sequence is enumerated. + +The previous example is correct and safe, because it uses the method to immediately evaluate the LINQ query and store the tasks in an array. This approach ensures the `id => GetUserAsync(id)` calls execute immediately and all tasks start concurrently, just like the `foreach` loop approach. + +**Problematic approach** (without immediate evaluation): + +```csharp +// DON'T do this - tasks won't start until enumerated. +var getUserTasks = userIds.Select(id => GetUserAsync(id)); // No .ToArray()! +return await Task.WhenAll(getUserTasks); // Tasks start here. +``` + +**Recommended approach**: + +```csharp +// DO this - tasks start immediately. +var getUserTasks = userIds.Select(id => GetUserAsync(id)).ToArray(); +return await Task.WhenAll(getUserTasks); +``` + +Always use or when creating tasks with LINQ to ensure immediate execution and concurrent task execution. ## Review considerations for asynchronous programming diff --git a/docs/csharp/includes/field-preview.md b/docs/csharp/includes/field-preview.md index b504bd1d668de..ba83ff9345bf8 100644 --- a/docs/csharp/includes/field-preview.md +++ b/docs/csharp/includes/field-preview.md @@ -7,6 +7,4 @@ ms.date: 10/30/2024 > [!IMPORTANT] > -> The `field` keyword is a preview feature in C# 13. You must be using .NET 9 and set your `` element to `preview` in your project file in order to use the `field` contextual keyword. -> -> You should be careful using the `field` keyword feature in a class that has a field named `field`. The new `field` keyword shadows a field named `field` in the scope of a property accessor. You can either change the name of the `field` variable, or use the `@` token to reference the `field` identifier as `@field`. You can learn more by reading the feature specification for [the `field` keyword](~/_csharplang/proposals/field-keyword.md). +> You should be careful using the `field` keyword feature in a class that has a field named `field`. The new `field` keyword shadows a field named `field` in the scope of a property accessor. You can either change the name of the `field` variable, or use the `@` token to reference the `field` identifier as `@field`. You can learn more by reading the feature specification for [the `field` keyword](~/_csharplang/proposals/csharp-14.0/field-keyword.md). diff --git a/docs/csharp/language-reference/compiler-messages/cs0051.md b/docs/csharp/language-reference/compiler-messages/cs0051.md index 8561af2472bfb..a56bfeb4b735f 100644 --- a/docs/csharp/language-reference/compiler-messages/cs0051.md +++ b/docs/csharp/language-reference/compiler-messages/cs0051.md @@ -1,7 +1,7 @@ --- description: "Compiler Error CS0051" title: "Compiler Error CS0051" -ms.date: 07/20/2015 +ms.date: 08/05/2025 f1_keywords: - "CS0051" helpviewer_keywords: @@ -12,17 +12,26 @@ ms.assetid: 62182e8d-c4a5-4853-a990-fd57a4f7c3b8 Inconsistent accessibility: parameter type 'type' is less accessible than method 'method' - The return type and each of the types referenced in the formal parameter list of a method must be at least as accessible as the method itself. Make sure the types used in method signatures are not accidentally private due to the omission of the `public` modifier. For more information, see [Access Modifiers](../../programming-guide/classes-and-structs/access-modifiers.md). +This error occurs when you declare a method (including constructors) with a parameter type that's less accessible than the method itself. For example, you might have a public constructor that uses an internal or private class as a parameter type. -## Example +The most common scenario is when you define a public method but one of its parameter types is internal or private. This creates an inconsistency because external code can see the method but can't access the types needed to call it. - The following sample generates CS0051: +## How to troubleshoot this error + +1. **Identify the parameter type causing the issue**: Look at the error message to see which parameter type is less accessible. +1. **Check the accessibility of the parameter type**: Right-click on the parameter type in your IDE and select "Go to Definition" (or press F12) to see how it's declared. +1. **Compare accessibility levels**: Ensure the parameter type is at least as accessible as the method that uses it. + +## Examples + +### Example 1: Public method with private parameter type + +The following sample generates CS0051 because the method `F` is public but the parameter type `B` is private: ```csharp // CS0051.cs public class A { - // Try making B public since F is public // B is implicitly private here. class B { @@ -37,3 +46,91 @@ public class A } } ``` + +### Example 2: Public constructor with internal parameter type + +This is a common scenario where you have a public constructor but the parameter type is internal: + +```csharp +// Another file or assembly. +internal class DatabaseConfiguration +{ + public string ConnectionString { get; set; } +} + +// In your main class. +public class DataService +{ + // This causes CS0051 because the constructor is public. + // but DatabaseConfiguration is internal. + public DataService(DatabaseConfiguration config) // CS0051 + { + // Implementation. + } +} +``` + +## To correct this error + +Choose one of the following approaches: + +1. **Make the parameter type more accessible**: Change the parameter type to match or exceed the accessibility of the method: + + ```csharp + public class A + { + // Make B public to match the accessibility of method F. + public class B + { + } + + public static void F(B b) // Now works correctly + { + } + } + ``` + +1. **Reduce the accessibility of the method**: Make the method less accessible to match the parameter type: + + ```csharp + public class A + { + class B // B remains private. + { + } + + // Make F internal or private to match B's accessibility. + internal static void F(B b) // Now works correctly + { + } + } + ``` + +1. **Use a more accessible interface or base class**: Instead of using the less accessible type directly, use a public interface or base class: + + ```csharp + public interface IConfiguration + { + string ConnectionString { get; } + } + + internal class DatabaseConfiguration : IConfiguration + { + public string ConnectionString { get; set; } + } + + public class DataService + { + // Use the public interface instead. + public DataService(IConfiguration config) // Works correctly + { + // Implementation. + } + } + ``` + +## See also + +- [Access Modifiers](../../programming-guide/classes-and-structs/access-modifiers.md) +- [Accessibility Levels](../keywords/accessibility-levels.md) +- [Constructors](../../programming-guide/classes-and-structs/constructors.md) diff --git a/docs/csharp/language-reference/compiler-messages/cs0518.md b/docs/csharp/language-reference/compiler-messages/cs0518.md index a0c45f1dd582b..b3ac64dc573cc 100644 --- a/docs/csharp/language-reference/compiler-messages/cs0518.md +++ b/docs/csharp/language-reference/compiler-messages/cs0518.md @@ -52,3 +52,5 @@ The main cause for this problem is that the project cannot access the predefined - Reinstall the .NET Framework common language runtime (if the previous solutions do not solve the problem). - Reload the project in Visual Studio. + +- Close Visual Studio, delete the `obj` and `bin` folders from your project directory, then reopen Visual Studio and rebuild the project. diff --git a/docs/csharp/language-reference/compiler-messages/partial-declarations.md b/docs/csharp/language-reference/compiler-messages/partial-declarations.md index 6563d19b8e1c5..9dbcfd384ebfd 100644 --- a/docs/csharp/language-reference/compiler-messages/partial-declarations.md +++ b/docs/csharp/language-reference/compiler-messages/partial-declarations.md @@ -250,6 +250,20 @@ Certain `partial` method declarations don't require an *implementing declaration When a partial method includes an implementing declaration, both declarations must be identical. Exactly one implementing declaration can be defined. +**CS0759** occurs when you have an *implementing declaration* (a partial method with a body) but no corresponding *defining declaration* (the method signature without a body). Every partial method with an implementation must have both declarations. + +The following example shows code that generates CS0759: + +:::code language="csharp" source="./snippets/partial-declarations/CS0759Examples.cs" id="IncorrectExample"::: + +To fix this error, add the defining declaration: + +:::code language="csharp" source="./snippets/partial-declarations/CS0759Examples.cs" id="CorrectExample"::: + +You can also place both declarations in the same partial class section: + +:::code language="csharp" source="./snippets/partial-declarations/CS0759Examples.cs" id="AlternativeCorrect"::: + ## Partial properties The following errors indicate mistakes in your partial property or indexer declarations: diff --git a/docs/csharp/language-reference/compiler-messages/snippets/partial-declarations/CS0759Examples.cs b/docs/csharp/language-reference/compiler-messages/snippets/partial-declarations/CS0759Examples.cs new file mode 100644 index 0000000000000..a954358dce03a --- /dev/null +++ b/docs/csharp/language-reference/compiler-messages/snippets/partial-declarations/CS0759Examples.cs @@ -0,0 +1,52 @@ +using System; + +namespace CS0759Examples +{ + // + // This will cause CS0759: No defining declaration found for implementing declaration of partial method. + // Uncomment the class below to see the CS0759 error: + /* + public partial class ExampleClass + { + // ERROR: This is an implementing declaration without a corresponding defining declaration + partial void MyMethod() // CS0759 + { + Console.WriteLine("Implementation without definition"); + } + } + */ + // + + // + // Correct way: Provide both the defining declaration and implementing declaration + public partial class CorrectExampleClass + { + // Defining declaration (signature without body) + partial void MyMethod(); + } + + public partial class CorrectExampleClass + { + // Implementing declaration (signature with body) + partial void MyMethod() + { + Console.WriteLine("This works correctly"); + } + } + // + + // + // Alternative correct approach: defining and implementing in same partial class + public partial class AlternativeExampleClass + { + // Defining declaration + partial void MyMethod(); + + // Implementing declaration in same partial class section + partial void MyMethod() + { + Console.WriteLine("This also works correctly"); + } + } + // +} \ No newline at end of file diff --git a/docs/csharp/language-reference/compiler-messages/snippets/partial-declarations/partial-declarations.csproj b/docs/csharp/language-reference/compiler-messages/snippets/partial-declarations/partial-declarations.csproj new file mode 100644 index 0000000000000..e33d07d003c30 --- /dev/null +++ b/docs/csharp/language-reference/compiler-messages/snippets/partial-declarations/partial-declarations.csproj @@ -0,0 +1,8 @@ + + + + net9.0 + enable + + + \ No newline at end of file diff --git a/docs/csharp/language-reference/compiler-options/code-generation.md b/docs/csharp/language-reference/compiler-options/code-generation.md index 5842b944eb6f9..dcffff9dd05f5 100644 --- a/docs/csharp/language-reference/compiler-options/code-generation.md +++ b/docs/csharp/language-reference/compiler-options/code-generation.md @@ -87,7 +87,11 @@ Causes the compiler to produce an assembly whose byte-for-byte output is identic true ``` -By default, compiler output from a given set of inputs is unique, since the compiler adds a timestamp and an MVID (a . Basically it is a GUID that uniquely identifies the module and version.) that is generated from random numbers. You use the `` option to produce a *deterministic assembly*, one whose binary content is identical across compilations as long as the input remains the same. In such a build, the timestamp and MVID fields will be replaced with values derived from a hash of all the compilation inputs. The compiler considers the following inputs that affect determinism: +For modern .NET projects, deterministic compilation is enabled by default (the `Deterministic` property defaults to `true`). When deterministic compilation is enabled, the timestamp and MVID fields are replaced with values derived from a hash of all the compilation inputs, ensuring identical binary output for identical inputs. + +When deterministic compilation is disabled (`false`), compiler output from a given set of inputs is unique, since the compiler adds a timestamp and an MVID (a . Basically it is a GUID that uniquely identifies the module and version.) that is generated from random numbers. + +You use the `` option to produce a *deterministic assembly*, one whose binary content is identical across compilations as long as the input remains the same. The compiler considers the following inputs that affect determinism: - The sequence of command-line parameters. - The contents of the compiler's .rsp response file. diff --git a/docs/csharp/language-reference/keywords/extension.md b/docs/csharp/language-reference/keywords/extension.md index a743f23b6b990..eba46e1d17b85 100644 --- a/docs/csharp/language-reference/keywords/extension.md +++ b/docs/csharp/language-reference/keywords/extension.md @@ -61,7 +61,7 @@ The equivalent extension method declarations demonstrate how those type paramete ## See also -- [Extensions feature specification](~/_csharplang/proposals/extensions.md) +- [Extensions feature specification](~/_csharplang/proposals/csharp-14.0/extensions.md) ## C# language specification diff --git a/docs/csharp/language-reference/operators/addition-operator.md b/docs/csharp/language-reference/operators/addition-operator.md index 14aea62365bda..9bced4a3457d1 100644 --- a/docs/csharp/language-reference/operators/addition-operator.md +++ b/docs/csharp/language-reference/operators/addition-operator.md @@ -72,7 +72,7 @@ A user-defined type can [overload](operator-overloading.md) the `+` operator. Wh ## C# language specification -For more information, see the [Unary plus operator](~/_csharpstandard/standard/expressions.md#1292-unary-plus-operator) and [Addition operator](~/_csharpstandard/standard/expressions.md#12105-addition-operator) sections of the [C# language specification](~/_csharpstandard/standard/README.md). For more information on overloading the compound assignment operators in C# 14 and later, see the [user defined compound assignment](~/_csharplang/proposals/user-defined-compound-assignment.md) feature specification. +For more information, see the [Unary plus operator](~/_csharpstandard/standard/expressions.md#1292-unary-plus-operator) and [Addition operator](~/_csharpstandard/standard/expressions.md#12105-addition-operator) sections of the [C# language specification](~/_csharpstandard/standard/README.md). For more information on overloading the compound assignment operators in C# 14 and later, see the [user defined compound assignment](~/_csharplang/proposals/csharp-14.0/user-defined-compound-assignment.md) feature specification. ## See also diff --git a/docs/csharp/language-reference/operators/arithmetic-operators.md b/docs/csharp/language-reference/operators/arithmetic-operators.md index f90246855393b..ddb2a74d2f169 100644 --- a/docs/csharp/language-reference/operators/arithmetic-operators.md +++ b/docs/csharp/language-reference/operators/arithmetic-operators.md @@ -290,7 +290,7 @@ For more information, see the following sections of the [C# language specificati - [Compound assignment](~/_csharpstandard/standard/expressions.md#12214-compound-assignment) - [The checked and unchecked operators](~/_csharpstandard/standard/expressions.md#12820-the-checked-and-unchecked-operators) - [Numeric promotions](~/_csharpstandard/standard/expressions.md#1247-numeric-promotions) -- [User defined compound assignment](~/_csharplang/proposals/user-defined-compound-assignment.md) +- [User defined compound assignment](~/_csharplang/proposals/csharp-14.0/user-defined-compound-assignment.md) ## See also diff --git a/docs/csharp/language-reference/operators/assignment-operator.md b/docs/csharp/language-reference/operators/assignment-operator.md index db8f86ff5bd12..d5c47a98de594 100644 --- a/docs/csharp/language-reference/operators/assignment-operator.md +++ b/docs/csharp/language-reference/operators/assignment-operator.md @@ -81,7 +81,7 @@ If a user-defined type overloads a binary operator `op`, the `op=` operator, if ## C# language specification -For more information, see the [Assignment operators](~/_csharpstandard/standard/expressions.md#1221-assignment-operators) section of the [C# language specification](~/_csharpstandard/standard/README.md) and the [User defined compound assignment](~/_csharplang/proposals/user-defined-compound-assignment.md) feature specification. +For more information, see the [Assignment operators](~/_csharpstandard/standard/expressions.md#1221-assignment-operators) section of the [C# language specification](~/_csharpstandard/standard/README.md) and the [User defined compound assignment](~/_csharplang/proposals/csharp-14.0/user-defined-compound-assignment.md) feature specification. ## See also diff --git a/docs/csharp/language-reference/operators/bitwise-and-shift-operators.md b/docs/csharp/language-reference/operators/bitwise-and-shift-operators.md index 3a8151e71719b..c4638e8f09701 100644 --- a/docs/csharp/language-reference/operators/bitwise-and-shift-operators.md +++ b/docs/csharp/language-reference/operators/bitwise-and-shift-operators.md @@ -201,7 +201,7 @@ For more information, see the following sections of the [C# language specificati - [Numeric promotions](~/_csharpstandard/standard/expressions.md#1247-numeric-promotions) - [C# 11 - Relaxed shift requirements](~/_csharplang/proposals/csharp-11.0/relaxing_shift_operator_requirements.md) - [C# 11 - Logical right-shift operator](~/_csharplang/proposals/csharp-11.0/unsigned-right-shift-operator.md) -- [User defined compound assignment](~/_csharplang/proposals/user-defined-compound-assignment.md) +- [User defined compound assignment](~/_csharplang/proposals/csharp-14.0/user-defined-compound-assignment.md) ## See also diff --git a/docs/csharp/language-reference/operators/boolean-logical-operators.md b/docs/csharp/language-reference/operators/boolean-logical-operators.md index 7360d387a25af..751c63970a1c8 100644 --- a/docs/csharp/language-reference/operators/boolean-logical-operators.md +++ b/docs/csharp/language-reference/operators/boolean-logical-operators.md @@ -194,7 +194,7 @@ For more information, see the following sections of the [C# language specificati - [Logical operators](~/_csharpstandard/standard/expressions.md#1213-logical-operators) - [Conditional logical operators](~/_csharpstandard/standard/expressions.md#1214-conditional-logical-operators) - [Compound assignment](~/_csharpstandard/standard/expressions.md#12214-compound-assignment) -- [User defined compound assignment](~/_csharplang/proposals/user-defined-compound-assignment.md) +- [User defined compound assignment](~/_csharplang/proposals/csharp-14.0/user-defined-compound-assignment.md) ## See also diff --git a/docs/csharp/language-reference/operators/subtraction-operator.md b/docs/csharp/language-reference/operators/subtraction-operator.md index 05d1743fe688d..bebeeaaa0ce0b 100644 --- a/docs/csharp/language-reference/operators/subtraction-operator.md +++ b/docs/csharp/language-reference/operators/subtraction-operator.md @@ -69,7 +69,7 @@ A user-defined type can [overload](operator-overloading.md) the `-` operator. Wh ## C# language specification -For more information, see the [Unary minus operator](~/_csharpstandard/standard/expressions.md#1293-unary-minus-operator) and [Subtraction operator](~/_csharpstandard/standard/expressions.md#12106-subtraction-operator) sections of the [C# language specification](~/_csharpstandard/standard/README.md). For more information on overloading the compound assignment operators in C# 14 and later, see the [user defined compound assignment](~/_csharplang/proposals/user-defined-compound-assignment.md) feature specification. +For more information, see the [Unary minus operator](~/_csharpstandard/standard/expressions.md#1293-unary-minus-operator) and [Subtraction operator](~/_csharpstandard/standard/expressions.md#12106-subtraction-operator) sections of the [C# language specification](~/_csharpstandard/standard/README.md). For more information on overloading the compound assignment operators in C# 14 and later, see the [user defined compound assignment](~/_csharplang/proposals/csharp-14.0/user-defined-compound-assignment.md) feature specification. ## See also diff --git a/docs/csharp/programming-guide/classes-and-structs/partial-classes-and-methods.md b/docs/csharp/programming-guide/classes-and-structs/partial-classes-and-methods.md index 4598d32d1c20d..6645c4a758237 100644 --- a/docs/csharp/programming-guide/classes-and-structs/partial-classes-and-methods.md +++ b/docs/csharp/programming-guide/classes-and-structs/partial-classes-and-methods.md @@ -149,7 +149,7 @@ partial void OnNameChanged() ## C# Language Specification -For more information, see [Partial types](~/_csharpstandard/standard/classes.md#1527-partial-type-declarations) and [Partial methods](~/_csharpstandard/standard/classes.md#1569-partial-methods) in the [C# Language Specification](~/_csharpstandard/standard/README.md). The language specification is the definitive source for C# syntax and usage. The new features for partial members are defined in the feature specifications for [extending partial methods](~/_csharplang/proposals/csharp-9.0/extending-partial-methods.md), [partial properties and indexers](~/_csharplang/proposals/csharp-13.0/partial-properties.md), and [partial events and constructors](~/_csharplang/proposals/partial-events-and-constructors.md). +For more information, see [Partial types](~/_csharpstandard/standard/classes.md#1527-partial-type-declarations) and [Partial methods](~/_csharpstandard/standard/classes.md#1569-partial-methods) in the [C# Language Specification](~/_csharpstandard/standard/README.md). The language specification is the definitive source for C# syntax and usage. The new features for partial members are defined in the feature specifications for [extending partial methods](~/_csharplang/proposals/csharp-9.0/extending-partial-methods.md), [partial properties and indexers](~/_csharplang/proposals/csharp-13.0/partial-properties.md), and [partial events and constructors](~/_csharplang/proposals/csharp-14.0/partial-events-and-constructors.md). ## See also diff --git a/docs/csharp/roslyn-sdk/tutorials/snippets/how-to-write-csharp-analyzer-code-fix/MakeConst/MakeConst.Test/MakeConst.Test.csproj b/docs/csharp/roslyn-sdk/tutorials/snippets/how-to-write-csharp-analyzer-code-fix/MakeConst/MakeConst.Test/MakeConst.Test.csproj index 18cfd360c40dc..01c05c7179397 100644 --- a/docs/csharp/roslyn-sdk/tutorials/snippets/how-to-write-csharp-analyzer-code-fix/MakeConst/MakeConst.Test/MakeConst.Test.csproj +++ b/docs/csharp/roslyn-sdk/tutorials/snippets/how-to-write-csharp-analyzer-code-fix/MakeConst/MakeConst.Test/MakeConst.Test.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/docs/csharp/specification/toc.yml b/docs/csharp/specification/toc.yml index c843abdd0f15c..12e21d99dc17b 100644 --- a/docs/csharp/specification/toc.yml +++ b/docs/csharp/specification/toc.yml @@ -80,7 +80,7 @@ items: - name: "Escape sequence '\\e'" href: ../../../_csharplang/proposals/csharp-13.0/esc-escape-sequence.md - name: "Ignored directives" - href: ../../../_csharplang/proposals/ignored-directives.md + href: ../../../_csharplang/proposals/csharp-14.0/ignored-directives.md - name: Basic concepts items: - name: Top-level statements @@ -120,7 +120,7 @@ items: - name: Conversions items: - name: First class span types - href: ../../../_csharplang/proposals/first-class-span-types.md + href: ../../../_csharplang/proposals/csharp-14.0/first-class-span-types.md - name: Patterns items: - name: Recursive pattern matching @@ -160,7 +160,7 @@ items: - name: Optional Lambda expression parameters href: ../../../_csharplang/proposals/csharp-12.0/lambda-method-group-defaults.md - name: Simple lambda parameters with modifiers - href: ../../../_csharplang/proposals/simple-lambda-parameters-with-modifiers.md + href: ../../../_csharplang/proposals/csharp-14.0/simple-lambda-parameters-with-modifiers.md - name: Checked user-defined operators href: ../../../_csharplang/proposals/csharp-11.0/checked-user-defined-operators.md - name: Unsigned right-shift operator @@ -172,13 +172,13 @@ items: - name: Extended nameof scope href: ../../../_csharplang/proposals/csharp-11.0/extended-nameof-scope.md - name: Unbound generic types in nameof - href: ../../../_csharplang/proposals/unbound-generic-types-in-nameof.md + href: ../../../_csharplang/proposals/csharp-14.0/unbound-generic-types-in-nameof.md - name: Overload resolution priority href: ../../../_csharplang/proposals/csharp-13.0/overload-resolution-priority.md - name: Null conditional assignment - href: ../../../_csharplang/proposals/null-conditional-assignment.md + href: ../../../_csharplang/proposals/csharp-14.0/null-conditional-assignment.md - name: User defined compound assignment operators - href: ../../../_csharplang/proposals/user-defined-compound-assignment.md + href: ../../../_csharplang/proposals/csharp-14.0/user-defined-compound-assignment.md - name: Statements items: - name: Global using directive @@ -204,9 +204,9 @@ items: - name: Partial properties href: ../../../_csharplang/proposals/csharp-13.0/partial-properties.md - name: Partial events and constructors - href: ../../../_csharplang/proposals/partial-events-and-constructors.md + href: ../../../_csharplang/proposals/csharp-14.0/partial-events-and-constructors.md - name: Field backed properties - href: ../../../_csharplang/proposals/field-keyword.md + href: ../../../_csharplang/proposals/csharp-14.0/field-keyword.md - name: Covariant return types href: ../../../_csharplang/proposals/csharp-9.0/covariant-returns.md - name: Primary constructors @@ -220,7 +220,7 @@ items: - name: Params collections href: ../../../_csharplang/proposals/csharp-13.0/params-collections.md - name: Extension members - href: ../../../_csharplang/proposals/extensions.md + href: ../../../_csharplang/proposals/csharp-14.0/extensions.md - name: Structs items: - name: Parameterless struct constructors diff --git a/docs/csharp/whats-new/csharp-14.md b/docs/csharp/whats-new/csharp-14.md index 18a0a50fc153a..09e4ab942ceb9 100644 --- a/docs/csharp/whats-new/csharp-14.md +++ b/docs/csharp/whats-new/csharp-14.md @@ -61,7 +61,7 @@ public static class Enumerable The members in the first extension block are called as though they're instance members of `IEnumerable`, for example `sequence.IsEmpty`. The members in the second extension block are called as though they're static members of `IEnumerable`, for example `IEnumerable.Identity`. -You can learn more details by reading the article on [extension members](../programming-guide/classes-and-structs/extension-methods.md) in the programming guide, the language reference article on the [`extension` keyword](../language-reference/keywords/extension.md), and the [feature specification](~/_csharplang/proposals/extensions.md) for the new extension members feature. +You can learn more details by reading the article on [extension members](../programming-guide/classes-and-structs/extension-methods.md) in the programming guide, the language reference article on the [`extension` keyword](../language-reference/keywords/extension.md), and the [feature specification](~/_csharplang/proposals/csharp-14.0/extensions.md) for the new extension members feature. ## The `field` keyword @@ -102,7 +102,7 @@ C# 14 introduces first-class support for ` and `ReadOnlySpan` are used in many key ways in C# and the runtime. Their introduction improves performance without risking safety. C# 14 recognizes the relationship and supports some conversions between `ReadOnlySpan`, `Span`, and `T[]`. The span types can be extension method receivers, compose with other conversions, and help with generic type inference scenarios. -You can find the list of implicit span conversions in the article on [built-in types](../language-reference/builtin-types/built-in-types.md) in the language reference section. You can learn more details by reading the feature specification for [First class span types](~/_csharplang/proposals/first-class-span-types.md). +You can find the list of implicit span conversions in the article on [built-in types](../language-reference/builtin-types/built-in-types.md) in the language reference section. You can learn more details by reading the feature specification for [First class span types](~/_csharplang/proposals/csharp-14.0/first-class-span-types.md). ## Unbound generic types and `nameof` @@ -140,7 +140,7 @@ The implementing declaration of a partial event must include `add` and `remove` ## User defined compound assignment -You can learn more in the feature specification for [user-defined compound assignment](~/_csharplang/proposals/user-defined-compound-assignment.md). +You can learn more in the feature specification for [user-defined compound assignment](~/_csharplang/proposals/csharp-14.0/user-defined-compound-assignment.md). ## Null-conditional assignment @@ -165,7 +165,7 @@ The right side of the `=` operator is evaluated only when the left side isn't nu In addition to assignment, you can use null-conditional member access operators with compound assignment operators (`+=`, `-=`, and others). However, increment and decrement, `++` and `--`, aren't allowed. -You can learn more in the language reference article on the [conditional member access](../language-reference/operators/member-access-operators.md#null-conditional-operators--and-) and the feature specification for [null-conditional assignment](~/_csharplang/proposals/null-conditional-assignment.md). +You can learn more in the language reference article on the [conditional member access](../language-reference/operators/member-access-operators.md#null-conditional-operators--and-) and the feature specification for [null-conditional assignment](~/_csharplang/proposals/csharp-14.0/null-conditional-assignment.md). ## See also diff --git a/docs/csharp/whats-new/tutorials/primary-constructors.md b/docs/csharp/whats-new/tutorials/primary-constructors.md index af1a68f52b4f6..6d5d7615b06d3 100644 --- a/docs/csharp/whats-new/tutorials/primary-constructors.md +++ b/docs/csharp/whats-new/tutorials/primary-constructors.md @@ -56,7 +56,7 @@ Consider the following code: :::code source="./snippets/primary-constructors/Distance.cs" id="MutableStruct"::: -In this example, the `Translate` method changes the `dx` and `dy` components, which requires the `Magnitude` and `Direction` properties be computed when accessed. The greater than or equal to (`=>`) operator designates an expression-bodied `get` accessor, whereas the equal to (`=`) operator designates an initializer. +In this example, the `Translate` method changes the `dx` and `dy` components, which requires the `Magnitude` and `Direction` properties be computed when accessed. The lambda operator (`=>`) designates an expression-bodied `get` accessor, whereas the equal-to operator (`=`) designates an initializer. This version of the code adds a parameterless constructor to the struct. The parameterless constructor must invoke the primary constructor, which ensures all primary constructor parameters are initialized. The primary constructor properties are accessed in a method, and the compiler creates hidden fields to represent each parameter. diff --git a/docs/orleans/tutorials-and-samples/snippets/minimal/Client/Client.csproj b/docs/orleans/tutorials-and-samples/snippets/minimal/Client/Client.csproj index 0cad47b96df20..f3a3ebc5b6b5c 100644 --- a/docs/orleans/tutorials-and-samples/snippets/minimal/Client/Client.csproj +++ b/docs/orleans/tutorials-and-samples/snippets/minimal/Client/Client.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/docs/orleans/tutorials-and-samples/snippets/minimal/GrainInterfaces/GrainInterfaces.csproj b/docs/orleans/tutorials-and-samples/snippets/minimal/GrainInterfaces/GrainInterfaces.csproj index 22fd91d314d32..4ba4ad4fccba3 100644 --- a/docs/orleans/tutorials-and-samples/snippets/minimal/GrainInterfaces/GrainInterfaces.csproj +++ b/docs/orleans/tutorials-and-samples/snippets/minimal/GrainInterfaces/GrainInterfaces.csproj @@ -7,7 +7,7 @@ - + diff --git a/docs/orleans/tutorials-and-samples/snippets/minimal/Grains/Grains.csproj b/docs/orleans/tutorials-and-samples/snippets/minimal/Grains/Grains.csproj index 56cc0228a4105..a2d57d006ed00 100644 --- a/docs/orleans/tutorials-and-samples/snippets/minimal/Grains/Grains.csproj +++ b/docs/orleans/tutorials-and-samples/snippets/minimal/Grains/Grains.csproj @@ -8,7 +8,7 @@ - + diff --git a/docs/orleans/tutorials-and-samples/snippets/minimal/Silo/Silo.csproj b/docs/orleans/tutorials-and-samples/snippets/minimal/Silo/Silo.csproj index 3d37884585a0a..6978230d1db2e 100644 --- a/docs/orleans/tutorials-and-samples/snippets/minimal/Silo/Silo.csproj +++ b/docs/orleans/tutorials-and-samples/snippets/minimal/Silo/Silo.csproj @@ -9,8 +9,8 @@ - - + +