diff --git a/docfx.json b/docfx.json index 4515a0c8ddaa6..1cfb7a4c9d176 100644 --- a/docfx.json +++ b/docfx.json @@ -57,7 +57,8 @@ "field-keyword.md", "unbound-generic-types-in-nameof.md", "first-class-span-types.md", - "simple-lambda-parameters-with-modifiers.md" + "simple-lambda-parameters-with-modifiers.md", + "partial-events-and-constructors.md" ], "src": "_csharplang/proposals", "dest": "csharp/language-reference/proposals", @@ -508,7 +509,7 @@ "_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": "02/14/2025", + "_csharplang/proposals/*.md": "03/11/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", @@ -686,7 +687,8 @@ "_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/simple-lambda-parameters-with-modifiers.md": "Simple lambda parameters with modifiers", + "_csharplang/proposals/partial-events-and-constructors.md": "Partial events and constructors", "_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", @@ -811,6 +813,7 @@ "_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 provides allows lambda parmaeters 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 provides allows partial events and constructors to be declared in partial classes. This allows the event and constructor to be split across class declarations.", "_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", diff --git a/docs/azure/includes/dotnet-all.md b/docs/azure/includes/dotnet-all.md index 118d8d7d685ab..47532b1c906f3 100644 --- a/docs/azure/includes/dotnet-all.md +++ b/docs/azure/includes/dotnet-all.md @@ -295,7 +295,7 @@ | Resource Management - Network Function | NuGet [1.0.0-beta.4](https://www.nuget.org/packages/Azure.ResourceManager.NetworkFunction/1.0.0-beta.4) | [docs](/dotnet/api/overview/azure/ResourceManager.NetworkFunction-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [1.0.0-beta.4](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.NetworkFunction_1.0.0-beta.4/sdk/networkfunction/Azure.ResourceManager.NetworkFunction/) | | Resource Management - New Relic Observability | NuGet [1.1.1](https://www.nuget.org/packages/Azure.ResourceManager.NewRelicObservability/1.1.1) | [docs](/dotnet/api/overview/azure/ResourceManager.NewRelicObservability-readme) | GitHub [1.1.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.NewRelicObservability_1.1.1/sdk/newrelicobservability/Azure.ResourceManager.NewRelicObservability/) | | Resource Management - Nginx | NuGet [1.0.0](https://www.nuget.org/packages/Azure.ResourceManager.Nginx/1.0.0)
NuGet [1.1.0-beta.3](https://www.nuget.org/packages/Azure.ResourceManager.Nginx/1.1.0-beta.3) | [docs](/dotnet/api/overview/azure/ResourceManager.Nginx-readme) | GitHub [1.0.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.Nginx_1.0.0/sdk/nginx/Azure.ResourceManager.Nginx/)
GitHub [1.1.0-beta.3](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.Nginx_1.1.0-beta.3/sdk/nginx/Azure.ResourceManager.Nginx/) | -| Resource Management - Notification Hubs | NuGet [1.1.1](https://www.nuget.org/packages/Azure.ResourceManager.NotificationHubs/1.1.1)
NuGet [1.2.0-beta.1](https://www.nuget.org/packages/Azure.ResourceManager.NotificationHubs/1.2.0-beta.1) | [docs](/dotnet/api/overview/azure/ResourceManager.NotificationHubs-readme) | GitHub [1.1.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.NotificationHubs_1.1.1/sdk/notificationhubs/Azure.ResourceManager.NotificationHubs/)
GitHub [1.2.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.NotificationHubs_1.2.0-beta.1/sdk/notificationhubs/Azure.ResourceManager.NotificationHubs/) | +| Resource Management - Notification Hubs | NuGet [1.1.1](https://www.nuget.org/packages/Azure.ResourceManager.NotificationHubs/1.1.1)
NuGet [1.2.0-beta.2](https://www.nuget.org/packages/Azure.ResourceManager.NotificationHubs/1.2.0-beta.2) | [docs](/dotnet/api/overview/azure/ResourceManager.NotificationHubs-readme) | GitHub [1.1.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.NotificationHubs_1.1.1/sdk/notificationhubs/Azure.ResourceManager.NotificationHubs/)
GitHub [1.2.0-beta.2](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.NotificationHubs_1.2.0-beta.2/sdk/notificationhubs/Azure.ResourceManager.NotificationHubs/) | | Resource Management - Oracle Database | NuGet [1.0.1](https://www.nuget.org/packages/Azure.ResourceManager.OracleDatabase/1.0.1) | [docs](/dotnet/api/overview/azure/ResourceManager.OracleDatabase-readme) | GitHub [1.0.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.OracleDatabase_1.0.1/sdk/oracle/Azure.ResourceManager.OracleDatabase/) | | Resource Management - Orbital | NuGet [1.1.0](https://www.nuget.org/packages/Azure.ResourceManager.Orbital/1.1.0) | [docs](/dotnet/api/overview/azure/ResourceManager.Orbital-readme) | GitHub [1.1.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.Orbital_1.1.0/sdk/orbital/Azure.ResourceManager.Orbital/) | | Resource Management - Palo Alto Networks - Next Generation Firewall | NuGet [1.1.0](https://www.nuget.org/packages/Azure.ResourceManager.PaloAltoNetworks.Ngfw/1.1.0) | [docs](/dotnet/api/overview/azure/ResourceManager.PaloAltoNetworks.Ngfw-readme) | GitHub [1.1.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.PaloAltoNetworks.Ngfw_1.1.0/sdk/paloaltonetworks.ngfw/Azure.ResourceManager.PaloAltoNetworks.Ngfw/) | diff --git a/docs/azure/includes/dotnet-new.md b/docs/azure/includes/dotnet-new.md index cfd430a49e447..db9ebf7e8f550 100644 --- a/docs/azure/includes/dotnet-new.md +++ b/docs/azure/includes/dotnet-new.md @@ -303,7 +303,7 @@ | Resource Management - Network Function | NuGet [1.0.0-beta.4](https://www.nuget.org/packages/Azure.ResourceManager.NetworkFunction/1.0.0-beta.4) | [docs](/dotnet/api/overview/azure/ResourceManager.NetworkFunction-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [1.0.0-beta.4](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.NetworkFunction_1.0.0-beta.4/sdk/networkfunction/Azure.ResourceManager.NetworkFunction/) | | Resource Management - New Relic Observability | NuGet [1.1.1](https://www.nuget.org/packages/Azure.ResourceManager.NewRelicObservability/1.1.1) | [docs](/dotnet/api/overview/azure/ResourceManager.NewRelicObservability-readme) | GitHub [1.1.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.NewRelicObservability_1.1.1/sdk/newrelicobservability/Azure.ResourceManager.NewRelicObservability/) | | Resource Management - Nginx | NuGet [1.0.0](https://www.nuget.org/packages/Azure.ResourceManager.Nginx/1.0.0)
NuGet [1.1.0-beta.3](https://www.nuget.org/packages/Azure.ResourceManager.Nginx/1.1.0-beta.3) | [docs](/dotnet/api/overview/azure/ResourceManager.Nginx-readme) | GitHub [1.0.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.Nginx_1.0.0/sdk/nginx/Azure.ResourceManager.Nginx/)
GitHub [1.1.0-beta.3](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.Nginx_1.1.0-beta.3/sdk/nginx/Azure.ResourceManager.Nginx/) | -| Resource Management - Notification Hubs | NuGet [1.1.1](https://www.nuget.org/packages/Azure.ResourceManager.NotificationHubs/1.1.1)
NuGet [1.2.0-beta.1](https://www.nuget.org/packages/Azure.ResourceManager.NotificationHubs/1.2.0-beta.1) | [docs](/dotnet/api/overview/azure/ResourceManager.NotificationHubs-readme) | GitHub [1.1.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.NotificationHubs_1.1.1/sdk/notificationhubs/Azure.ResourceManager.NotificationHubs/)
GitHub [1.2.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.NotificationHubs_1.2.0-beta.1/sdk/notificationhubs/Azure.ResourceManager.NotificationHubs/) | +| Resource Management - Notification Hubs | NuGet [1.1.1](https://www.nuget.org/packages/Azure.ResourceManager.NotificationHubs/1.1.1)
NuGet [1.2.0-beta.2](https://www.nuget.org/packages/Azure.ResourceManager.NotificationHubs/1.2.0-beta.2) | [docs](/dotnet/api/overview/azure/ResourceManager.NotificationHubs-readme) | GitHub [1.1.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.NotificationHubs_1.1.1/sdk/notificationhubs/Azure.ResourceManager.NotificationHubs/)
GitHub [1.2.0-beta.2](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.NotificationHubs_1.2.0-beta.2/sdk/notificationhubs/Azure.ResourceManager.NotificationHubs/) | | Resource Management - Oracle Database | NuGet [1.0.1](https://www.nuget.org/packages/Azure.ResourceManager.OracleDatabase/1.0.1) | [docs](/dotnet/api/overview/azure/ResourceManager.OracleDatabase-readme) | GitHub [1.0.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.OracleDatabase_1.0.1/sdk/oracle/Azure.ResourceManager.OracleDatabase/) | | Resource Management - Orbital | NuGet [1.1.0](https://www.nuget.org/packages/Azure.ResourceManager.Orbital/1.1.0) | [docs](/dotnet/api/overview/azure/ResourceManager.Orbital-readme) | GitHub [1.1.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.Orbital_1.1.0/sdk/orbital/Azure.ResourceManager.Orbital/) | | Resource Management - Palo Alto Networks - Next Generation Firewall | NuGet [1.1.0](https://www.nuget.org/packages/Azure.ResourceManager.PaloAltoNetworks.Ngfw/1.1.0) | [docs](/dotnet/api/overview/azure/ResourceManager.PaloAltoNetworks.Ngfw-readme) | GitHub [1.1.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.PaloAltoNetworks.Ngfw_1.1.0/sdk/paloaltonetworks.ngfw/Azure.ResourceManager.PaloAltoNetworks.Ngfw/) | diff --git a/docs/azure/sdk/authentication/additional-methods.md b/docs/azure/sdk/authentication/additional-methods.md index f64fd790ac715..d49e22478e31a 100644 --- a/docs/azure/sdk/authentication/additional-methods.md +++ b/docs/azure/sdk/authentication/additional-methods.md @@ -3,7 +3,7 @@ title: Additional methods to authenticate to Azure from .NET apps description: This article describes additional, less common methods you can use to authenticate your .NET app to Azure resources. ms.topic: how-to ms.custom: devx-track-dotnet, engagement-fy23 -ms.date: 08/15/2024 +ms.date: 03/14/2025 --- # Additional methods to authenticate to Azure resources from .NET apps @@ -115,14 +115,3 @@ This method interactively authenticates a user on devices with limited UI (typic For more information, see [Microsoft identity platform and the OAuth 2.0 device authorization grant flow](/entra/identity-platform/v2-oauth2-device-code). Device code authentication in a development environment enables the application for all operations allowed by the interactive login credentials. As a result, if you're the owner or administrator of your subscription, your code has inherent access to most resources in that subscription without having to assign any specific permissions. However, you can use this method with a specific client ID, rather than the default, for which you can assign specific permissions. - -## Username and password authentication - -This method authenticates an application using previously collected credentials and the [UsernamePasswordCredential](/dotnet/api/azure.identity.usernamepasswordcredential) object. - -> [!IMPORTANT] -> This method of authentication is discouraged because it's less secure than other flows. Also, this method isn't interactive and is therefore **incompatible with any form of multi-factor authentication or consent prompting.** The application must already have consent from the user or a directory administrator. -> -> Furthermore, this method authenticates only work and school accounts; Microsoft accounts aren't supported. For more information, see [Sign up your organization to use Microsoft Entra ID](/entra/fundamentals/sign-up-organization). - -:::code language="csharp" source="../snippets/authentication/additional-auth/username-password/Program.cs" highlight="10-12"::: diff --git a/docs/azure/sdk/authentication/create-token-credentials-from-configuration.md b/docs/azure/sdk/authentication/create-token-credentials-from-configuration.md index 34b08494f1277..34251e6061cda 100644 --- a/docs/azure/sdk/authentication/create-token-credentials-from-configuration.md +++ b/docs/azure/sdk/authentication/create-token-credentials-from-configuration.md @@ -1,38 +1,39 @@ --- -title: Create token credentials from configuration -description: This article describes how to create Microsoft Entra token credentials from configuration files. +title: Create Azure Identity library credentials via configuration files +description: Learn how to create token credentials from configuration files. ms.topic: how-to ms.custom: devx-track-dotnet, engagement-fy23 -ms.date: 02/19/2025 +ms.date: 03/14/2025 --- -# Create Microsoft Entra credential types using configuration files +# Create Azure Identity library credentials via configuration files -The `Microsoft.Extensions.Azure` library supports creating different types from key-value pairs defined in _appsettings.json_ and other configuration files. The credential types correspond to a subset of the [credential classes](/dotnet/api/overview/azure/identity-readme) in the Azure Identity client library. This article describes the support for different `TokenCredential` types and how to configure the required key-value pairs for each type. +The [Azure client library integration for ASP.NET Core](/dotnet/api/overview/azure/microsoft.extensions.azure-readme?view=azure-dotnet&preserve-view=true) (`Microsoft.Extensions.Azure`) supports creating different types from key-value pairs defined in _appsettings.json_ and other configuration files. The credentials correspond to a subset of the [credential classes](/dotnet/api/overview/azure/identity-readme?view=azure-dotnet&preserve-view=true#credential-classes) in the Azure Identity client library. This article describes the support for different `TokenCredential` types and how to configure the required key-value pairs for each type. ## Support for Azure credentials through configuration -The [`Microsoft.Extensions.Azure`](https://www.nuget.org/packages/Microsoft.Extensions.Azure) library can automatically provide Azure service clients with a `TokenCredential` class by searching _appsettings.json_ or other configuration files for credential values using the `IConfiguration` abstraction for .NET. This approach allows developers to explicitly set credential values across different environments through configuration rather than through app code directly. +`Microsoft.Extensions.Azure` can automatically provide Azure service clients with a `TokenCredential` class by searching _appsettings.json_ or other configuration files for credential values using the `IConfiguration` abstraction for .NET. This approach allows developers to explicitly set credential values across different environments through configuration rather than through app code directly. -The following credential types are supported via configuration: +The following credentials can be created via configuration: -* [ClientCertificateCredential](#create-a-clientcertificatecredential-type) -* [ClientSecretCredential](#create-a-clientsecretcredential-type) -* [DefaultAzureCredential](#create-a-defaultazurecredential-type) -* [ManagedIdentityCredential](#create-a-managedidentitycredential-type) -* [WorkloadIdentityCredential](#create-a-workloadidentitycredential-type) +* [AzurePipelinesCredential](#create-an-instance-of-azurepipelinescredential) +* [ClientCertificateCredential](#create-an-instance-of-clientcertificatecredential) +* [ClientSecretCredential](#create-an-instance-of-clientsecretcredential) +* [DefaultAzureCredential](#create-an-instance-of-defaultazurecredential) +* [ManagedIdentityCredential](#create-an-instance-of-managedidentitycredential) +* [WorkloadIdentityCredential](#create-an-instance-of-workloadidentitycredential) ## Configure Azure credentials -Azure service clients registered with the method are automatically configured with an instance of `DefaultAzureCredential` if no explicit credential is supplied via the extension method. You can also override the global `DefaultAzureCredential` using credential values from configuration files when registering a client to create a specific credential type: +Azure service clients registered with the method are automatically configured with an instance of `DefaultAzureCredential` if no explicit credential is supplied via the extension method. You can also override the global `DefaultAzureCredential` using credential values from configuration files when registering a client to create a specific credential: ```csharp builder.Services.AddAzureClients(clientBuilder => { - // Register BlobServiceClient using credentials from appsettings.json + // Register BlobServiceClient using credential from appsettings.json clientBuilder.AddBlobServiceClient(builder.Configuration.GetSection("Storage")); - // Register ServiceBusClient using the fallback DefaultAzureCredential credentials + // Register ServiceBusClient using the fallback DefaultAzureCredential clientBuilder.AddServiceBusClientWithNamespace( ".servicebus.windows.net"); }); @@ -44,27 +45,29 @@ The associated _appsettings.json_ file: "Storage": { "serviceUri": "", "credential": "managedidentity", - "clientId": "" + "clientId": "" } ``` -The following credential types also support the `AdditionallyAllowedTenants` property, which specifies additional Microsoft Entra tenants beyond the default tenant for which the credential may acquire tokens: +The following credentials also support the `AdditionallyAllowedTenants` property, which specifies Microsoft Entra tenants beyond the default tenant for which the credential can acquire tokens: -* [ClientCertificateCredential](#create-a-clientcertificatecredential-type) -* [ClientSecretCredential](#create-a-clientsecretcredential-type) -* [DefaultAzureCredential](#create-a-defaultazurecredential-type) +* [AzurePipelinesCredential](#create-an-instance-of-azurepipelinescredential) +* [ClientCertificateCredential](#create-an-instance-of-clientcertificatecredential) +* [ClientSecretCredential](#create-an-instance-of-clientsecretcredential) +* [DefaultAzureCredential](#create-an-instance-of-defaultazurecredential) +* [WorkloadIdentityCredential](#create-an-instance-of-workloadidentitycredential) -Add the wildcard value "*" to allow the credential to acquire tokens for any Microsoft Entra tenant the logged in account can access. If no tenant IDs are specified, this option will have no effect on that authentication method, and the credential will acquire tokens for any requested tenant when using that method. +Add the wildcard value `*` to allow the credential to acquire tokens for any Microsoft Entra tenant the logged in account can access. If no tenant IDs are specified, this option has no effect on that authentication method, and the credential will acquire tokens for any requested tenant when using that method. ```json { - "additionallyAllowedTenants": "" + "additionallyAllowedTenants": "" } ``` -### Create a `ManagedIdentityCredential` type +### Create an instance of `ManagedIdentityCredential` -You can create both user-assigned and system-assigned managed identities using configuration values. Add the following key-value pairs to your _appsettings.json_ file to create an instance of . +You can create both user-assigned and system-assigned managed identities using configuration values. To create an instance of , add the following key-value pairs to your _appsettings.json_ file. #### User-assigned managed identities @@ -75,7 +78,7 @@ A user-assigned managed identity can be used by providing a client ID, resource ```json { "credential": "managedidentity", - "clientId": "" + "clientId": "" } ``` @@ -84,7 +87,7 @@ A user-assigned managed identity can be used by providing a client ID, resource ```json { "credential": "managedidentity", - "managedIdentityResourceId": "" + "managedIdentityResourceId": "" } ``` @@ -96,7 +99,7 @@ The resource ID takes the form: ```json { "credential": "managedidentity", - "managedIdentityObjectId": "" + "managedIdentityObjectId": "" } ``` @@ -113,56 +116,75 @@ The resource ID takes the form: } ``` -### Create a `WorkloadIdentityCredential` type +### Create an instance of `AzurePipelinesCredential` -Add the following key-value pairs to your _appsettings.json_ file to create an : +To create an instance of , add the following key-value pairs to your _appsettings.json_ file: + +```json +{ + "credential": "azurepipelines", + "clientId": "", + "tenantId": "", + "serviceConnectionId": "", + "systemAccessToken": "" +} +``` + +> [!IMPORTANT] +> `AzurePipelinesCredential` is supported in `Microsoft.Extensions.Azure` versions 1.11.0 and later. + +### Create an instance of `WorkloadIdentityCredential` + +To create an instance of , add the following key-value pairs to your _appsettings.json_ file: ```json { "credential": "workloadidentity", - "tenantId": "", - "clientId": "", - "tokenFilePath": "" + "tenantId": "", + "clientId": "", + "tokenFilePath": "" } ``` -### Create a `ClientSecretCredential` type +### Create an instance of `ClientSecretCredential` -Add the following key-value pairs to your _appsettings.json_ file to create an : +To create an instance of , add the following key-value pairs to your _appsettings.json_ file: ```json { - "tenantId": "", - "clientId": "", - "clientSecret": "" + "tenantId": "", + "clientId": "", + "clientSecret": "" } ``` -### Create a `ClientCertificateCredential` type +### Create an instance of `ClientCertificateCredential` -Add the following key-value pairs to your _appsettings.json_ file to create an : +To create an instance of , add the following key-value pairs to your _appsettings.json_ file: ```json { - "tenantId": "", - "clientId": "", - "clientCertificate": "", - "clientCertificateStoreLocation": "", - "additionallyAllowedTenants": "" + "tenantId": "", + "clientId": "", + "clientCertificate": "", + "clientCertificateStoreLocation": "" } ``` > [!NOTE] -> The `clientCertificateStoreLocation` and `additionallyAllowedTenants` key-value pairs are optional. If the keys are present and have empty values, they are ignored. If no `clientCertificateStoreLocation` is specified, the default `CurrentUser` is used from the enum. +> The `clientCertificateStoreLocation` key is optional. If the key: +> +> * Is present and has an empty value, it's ignored. +> * Isn't present, the default `CurrentUser` is used from the enum. -### Create a `DefaultAzureCredential` type +### Create an instance of `DefaultAzureCredential` -Add the following key-value pairs to your _appsettings.json_ file to create an : +To create an instance of , add the following key-value pairs to your _appsettings.json_ file: ```json { - "tenantId": "", - "clientId": "", - "managedIdentityResourceId": "" + "tenantId": "", + "clientId": "", + "managedIdentityResourceId": "" } ``` diff --git a/docs/azure/sdk/authentication/local-development-dev-accounts.md b/docs/azure/sdk/authentication/local-development-dev-accounts.md index 006ce33f9aa53..e83b217451873 100644 --- a/docs/azure/sdk/authentication/local-development-dev-accounts.md +++ b/docs/azure/sdk/authentication/local-development-dev-accounts.md @@ -3,171 +3,101 @@ title: Authenticate .NET apps to Azure using developer accounts description: Learn how to authenticate your application to Azure services when using the Azure SDK for .NET during local development using developer accounts. ms.topic: how-to ms.custom: devx-track-dotnet, engagement-fy23, devx-track-azurecli -ms.date: 07/31/2024 +ms.date: 03/14/2025 --- # Authenticate .NET apps to Azure services during local development using developer accounts -Developers need to debug and test cloud apps on their local workstations. When an app runs on a developer's workstation during local development, it must still authenticate to any Azure services used by the app. This article covers how to use a developer's Azure credentials to authenticate the app to Azure during local development. +During local development, applications need to authenticate to Azure to access various Azure services. Two common approaches for local authentication are to [use a service principal](local-development-service-principal.md) or to use a developer account. This article explains how to use a developer account. In the sections ahead, you learn: + +- How to use Microsoft Entra groups to efficiently manage permissions for multiple developer accounts +- How to assign roles to developer accounts to scope permissions +- How to sign-in to supported local development tools +- How to authenticate using a developer account from your app code :::image type="content" source="../media/local-dev-dev-accounts-overview.png" alt-text="A diagram showing an app running in local development using a developer tool identity to connect to Azure resources."::: -For an app to authenticate to Azure during local development using the developer's Azure credentials, the developer must be signed in to Azure from one of the following developer tools: +For an app to authenticate to Azure during local development using the developer's Azure credentials, the developer must be signed-in to Azure from one of the following developer tools: -- Visual Studio - Azure CLI - Azure Developer CLI - Azure PowerShell +- Visual Studio -The Azure Identity library can detect that the developer is signed in from one of these tools. The library can then obtain the Microsoft Entra access token via the tool to authenticate the app to Azure as the signed-in user. - -This approach is easiest to set up for a development team since it takes advantage of the developers' existing Azure accounts. However, a developer's account likely has more permissions than required by the app, therefore exceeding the permissions the app runs with in production. As an alternative, you can [create application service principals to use during local development](./local-development-service-principal.md), which can be scoped to have only the access needed by the app. - -## 1 - Create Microsoft Entra group for local development - -Since there are almost always multiple developers who work on an app, a Microsoft Entra group is recommended to encapsulate the roles (permissions) the app needs in local development. This approach offers the following advantages: - -- Every developer is assured to have the same roles assigned since roles are assigned at the group level. -- If a new role is needed for the app, it only needs to be added to the group for the app. -- If a new developer joins the team, they gain the necessary permissions to work on the app after being added to the group. - -If you have an existing Microsoft Entra group for your development team, you can use that group. Otherwise, complete the following steps to create a Microsoft Entra group. - -### [Azure portal](#tab/azure-portal) - -| Instructions | Screenshot | -|:----------------|-----------:| -| [!INCLUDE [Create app group step 1](<../includes/local-dev-accounts-app-group-azure-portal-1.md>)] | :::image type="content" source="../media/local-dev-accounts-app-group-azure-portal-1-240px.png" alt-text="A screenshot showing how to use the top search bar in the Azure portal to search for and navigate to the Microsoft Entra ID page." lightbox="../media/local-dev-accounts-app-group-azure-portal-1.png"::: | -| [!INCLUDE [Create app group step 2](<../includes/local-dev-accounts-app-group-azure-portal-2.md>)] | :::image type="content" source="../media/local-dev-accounts-app-group-azure-portal-2-240px.png" alt-text="A screenshot showing the location of the Groups menu item in the left-hand menu of the Microsoft Entra ID Default Directory page." lightbox="../media/local-dev-accounts-app-group-azure-portal-2.png"::: | -| [!INCLUDE [Create app group step 3](<../includes/local-dev-accounts-app-group-azure-portal-3.md>)] | :::image type="content" source="../media/local-dev-accounts-app-group-azure-portal-3-240px.png" alt-text="A screenshot showing the location of the New Group button in the All groups page." lightbox="../media/local-dev-accounts-app-group-azure-portal-3.png"::: | -| [!INCLUDE [Create app group step 4](<../includes/local-dev-accounts-app-group-azure-portal-4.md>)] | :::image type="content" source="../media/local-dev-accounts-app-group-azure-portal-4-240px.png" alt-text="A screenshot showing how to create a new Microsoft Entra group. The location of the link to select to add members to this group is highlighted." lightbox="../media/local-dev-accounts-app-group-azure-portal-4.png"::: | -| [!INCLUDE [Create app group step 5](<../includes/local-dev-accounts-app-group-azure-portal-5.md>)] | :::image type="content" source="../media/local-dev-accounts-app-group-azure-portal-5-240px.png" alt-text="A screenshot of the Add members dialog box showing how to select developer accounts to be included in the group." lightbox="../media/local-dev-accounts-app-group-azure-portal-5.png"::: | -| [!INCLUDE [Create app group step 6](<../includes/local-dev-accounts-app-group-azure-portal-6.md>)] | :::image type="content" source="../media/local-dev-accounts-app-group-azure-portal-6-240px.png" alt-text="A screenshot of the New Group page showing how to complete the process by selecting the Create button." lightbox="../media/local-dev-accounts-app-group-azure-portal-6.png"::: | - -### [Azure CLI](#tab/azure-cli) - -The [az ad group create](/cli/azure/ad/group#az-ad-group-create) command is used to create groups in Microsoft Entra ID. The `--display-name` and `--mail-nickname` parameters are required. The name given to the group should be based on the app's name. It's also useful to include a phrase like 'local-dev' in the group name to indicate the group's purpose. - -```azurecli -az ad group create \ - --display-name MyDisplay \ - --mail-nickname MyDisplay \ - --description -``` - -Copy the value of the `id` property in the output of the command. This `id` property represents the group's object ID. You need it in later steps. You can also use the [az ad group show](/cli/azure/ad/group#az-ad-group-show) command to retrieve this property. +The Azure Identity library can detect that the developer is signed-in from one of these tools. The library can then obtain the Microsoft Entra access token via the tool to authenticate the app to Azure as the signed-in user. -To add members to the group, you need the object ID of the Azure user. Use the [az ad user list](/cli/azure/ad/sp#az-ad-user-list) command to list the available service principals. The `--filter` parameter command accepts OData-style filters and can be used to filter the list on the display name of the user as shown. The `--query` parameter limits the output to columns of interest. +This approach takes advantage of the developer's existing Azure accounts to streamline the authentication process. However, a developer's account likely has more permissions than required by the app, therefore exceeding the permissions the app runs with in production. As an alternative, you can [create application service principals to use during local development](./local-development-service-principal.md), which can be scoped to have only the access needed by the app. -```azurecli -az ad user list \ - --filter "startswith(displayName, 'Bob')" \ - --query "[].{objectId:id, displayName:displayName}" \ - --output table -``` +[!INCLUDE [auth-create-entra-group](../includes/auth-create-entra-group.md)] -The [az ad group member add](/cli/azure/ad/group/member#az-ad-group-member-add) command can then be used to add members to a group: +[!INCLUDE [auth-assign-group-roles](../includes/auth-assign-group-roles.md)] -```azurecli -az ad group member add \ - --group \ - --member-id -``` - ---- +## Sign-in to Azure using developer tooling -> [!NOTE] -> By default, the creation of Microsoft Entra groups is limited to certain privileged roles in a directory. If you're unable to create a group, contact an administrator for your directory. If you're unable to add members to an existing group, contact the group owner or a directory administrator. To learn more, see [Manage Microsoft Entra groups and group membership](/entra/fundamentals/how-to-manage-groups). +Next, sign-in to Azure using one of several developer tools that can be used to perform authentication in your development environment. The account you authenticate should also exist in the Microsoft Entra group you created and configured earlier. -## 2 - Assign roles to the Microsoft Entra group +### [Visual Studio](#tab/sign-in-visual-studio) -Next, determine what roles (permissions) your app needs on what resources and assign those roles to your app. In this example, the roles are assigned to the Microsoft Entra group created in step 1. Groups can be assigned a role at a resource, resource group, or subscription scope. This example shows how to assign roles at the resource group, scope since most apps group all their Azure resources into a single resource group. +Developers using Visual Studio 2017 or later can authenticate using their developer account through the IDE. Apps using `DefaultAzureCredential` or can discover and use this account to authenticate app requests when running locally. -### [Azure portal](#tab/azure-portal) +1. Inside Visual Studio, navigate to **Tools** > **Options** to open the options dialog. +1. In the **Search Options** box at the top, type *Azure* to filter the available options. +1. Under **Azure Service Authentication**, choose **Account Selection**. +1. Select the drop-down menu under **Choose an account** and choose to add a Microsoft Account. +1. In the window that opens, enter the credentials for your desired Azure account, and then confirm your inputs. -| Instructions | Screenshot | -|:----------------|-----------:| -| [!INCLUDE [Assign dev service principal to role step 1](<../includes/assign-local-dev-group-to-role-azure-portal-1.md>)] | :::image type="content" source="../media/assign-local-dev-group-to-role-azure-portal-1-240px.png" alt-text="A screenshot showing how to use the top search box in the Azure portal to locate and navigate to the resource group you want to assign roles (permissions) to." lightbox="../media/assign-local-dev-group-to-role-azure-portal-1.png"::: | -| [!INCLUDE [Assign dev service principal to role step 1](<../includes/assign-local-dev-group-to-role-azure-portal-2.md>)] | :::image type="content" source="../media/assign-local-dev-group-to-role-azure-portal-2-240px.png" alt-text="A screenshot of the resource group page showing the location of the Access control (IAM) menu item." lightbox="../media/assign-local-dev-group-to-role-azure-portal-2.png"::: | -| [!INCLUDE [Assign dev service principal to role step 1](<../includes/assign-local-dev-group-to-role-azure-portal-3.md>)] | :::image type="content" source="../media/assign-local-dev-group-to-role-azure-portal-3-240px.png" alt-text="A screenshot showing how to navigate to the role assignments tab and the location of the button used to add role assignments to a resource group." lightbox="../media/assign-local-dev-group-to-role-azure-portal-3.png"::: | -| [!INCLUDE [Assign dev service principal to role step 1](<../includes/assign-local-dev-group-to-role-azure-portal-4.md>)] | :::image type="content" source="../media/assign-local-dev-group-to-role-azure-portal-4-240px.png" alt-text="A screenshot showing how to filter and select role assignments to be added to the resource group." lightbox="../media/assign-local-dev-group-to-role-azure-portal-4.png"::: | -| [!INCLUDE [Assign dev service principal to role step 1](<../includes/assign-local-dev-group-to-role-azure-portal-5.md>)] | :::image type="content" source="../media/assign-local-dev-group-to-role-azure-portal-5-240px.png" alt-text="A screenshot showing the radio button to select to assign a role to a Microsoft Entra group and the link used to select the group to assign the role to." lightbox="../media/assign-local-dev-group-to-role-azure-portal-5.png"::: | -| [!INCLUDE [Assign dev service principal to role step 1](<../includes/assign-local-dev-group-to-role-azure-portal-6.md>)] | :::image type="content" source="../media/assign-local-dev-group-to-role-azure-portal-6-240px.png" alt-text="A screenshot showing how to filter for and select the Microsoft Entra group for the application in the Select members dialog box." lightbox="../media/assign-local-dev-group-to-role-azure-portal-6.png"::: | -| [!INCLUDE [Assign dev service principal to role step 1](<../includes/assign-local-dev-group-to-role-azure-portal-7.md>)] | :::image type="content" source="../media/assign-local-dev-group-to-role-azure-portal-7-240px.png" alt-text="A screenshot showing the completed Add role assignment page and the location of the Review + assign button used to complete the process." lightbox="../media/assign-local-dev-group-to-role-azure-portal-7.png"::: | + :::image type="content" source="../media/visual-studio-sign-in.png" alt-text="A screenshot showing how to sign-in to Azure using Visual Studio."::: -### [Azure CLI](#tab/azure-cli) +1. Select **OK** to close the options dialog. -An application service principal is assigned a role in Azure using the [az role assignment create](/cli/azure/role/assignment) command: +### [Azure CLI](#tab/sign-in-azure-cli) -```azurecli -az role assignment create \ - --assignee "{appId}" \ - --role "{roleName}" \ - --resource-group "{resourceGroupName}" -``` +Developers coding outside of an IDE can also use the [Azure CLI](/cli/azure/what-is-azure-cli) to authenticate. Apps using `DefaultAzureCredential` or can then use this account to authenticate app requests when running locally. -To get the role names that a service principal can be assigned to, use the [az role definition list](/cli/azure/role/definition#az-role-definition-list) command: +To authenticate with the Azure CLI, run the `az login` command. On a system with a default web browser, the Azure CLI launches the browser to authenticate the user. ```azurecli -az role definition list \ - --query "sort_by([].{roleName:roleName, description:description}, &roleName)" \ - --output table +az login ``` -For example, to allow the application service principal with the appId of `00000000-0000-0000-0000-000000000000` read, write, and delete access to Azure Storage blob containers and data to all storage accounts in the *msdocs-dotnet-sdk-auth-example* resource group, you would assign the application service principal to the *Storage Blob Data Contributor* role using the following command: +For systems without a default web browser, the `az login` command uses the device code authentication flow. The user can also force the Azure CLI to use the device code flow rather than launching a browser by specifying the `--use-device-code` argument. ```azurecli -az role assignment create \ - --assignee "00000000-0000-0000-0000-000000000000" \ - --role "Storage Blob Data Contributor" \ - --resource-group "msdocs-dotnet-sdk-auth-example" +az login --use-device-code ``` -For information on assigning permissions at the resource or subscription level using the Azure CLI, see [Assign Azure roles using the Azure CLI](/azure/role-based-access-control/role-assignments-cli). - ---- - -## 3 - Sign in to Azure using developer tooling - -Next, sign in to Azure using one of several developer tools. The account you authenticate should also exist in the Microsoft Entra group you created and configured earlier. - -### [Visual Studio](#tab/sign-in-visual-studio) - -1. Navigate to **Tools** > **Options** to open the options dialog. -1. In the **Search Options** box at the top, type *Azure* to filter the available options. -1. Under **Azure Service Authentication**, choose **Account Selection**. -1. Select the drop-down menu under **Choose an account** and choose to add a Microsoft Account. A window opens, prompting you to pick an account. Enter the credentials for your desired Azure account, and then select the confirmation. - - :::image type="content" source="../media/visual-studio-sign-in.png" alt-text="A screenshot showing how to sign in to Azure using Visual Studio."::: - -1. Select **OK** to close the options dialog. +### [Azure Developer CLI](#tab/sign-in-azure-developer-cli) -### [Azure CLI](#tab/sign-in-azure-cli) +Developers coding outside of an IDE can also use the [Azure Developer CLI](/azure/developer/azure-developer-cli/overview) to authenticate. Apps using `DefaultAzureCredential` or can then use this account to authenticate app requests when running locally. -Open a terminal on your developer workstation and sign in to Azure from the [Azure CLI](/cli/azure/what-is-azure-cli): +To authenticate with the Azure Developer CLI, run the `azd auth login` command. On a system with a default web browser, the Azure Developer CLI launches the browser to authenticate the user. -```azurecli -az login +```azdeveloper +azd auth login ``` -### [Azure Developer CLI](#tab/sign-in-azure-developer-cli) - -Open a terminal on your developer workstation and sign in to Azure from the [Azure Developer CLI](/azure/developer/azure-developer-cli/overview): +For systems without a default web browser, the `azd auth login --use-device-code` uses the device code authentication flow. The user can also force the the Azure Developer CLI to use the device code flow rather than launching a browser by specifying the `--use-device-code` argument. ```azdeveloper -azd auth login +azd auth login --use-device-code ``` ### [Azure PowerShell](#tab/sign-in-azure-powershell) -Open a terminal on your developer workstation and sign in to Azure from [Azure PowerShell](/powershell/azure/what-is-azure-powershell): +Developers coding outside of an IDE can also use [Azure PowerShell](/powershell/azure/what-is-azure-powershell) to authenticate. Apps using `DefaultAzureCredential` or can then use this account to authenticate app requests when running locally. + +To authenticate with Azure PowerShell, run the command `Connect-AzAccount`. On a system with a default web browser and version 5.0.0 or later of Azure PowerShell, it launches the browser to authenticate the user. ```azurepowershell Connect-AzAccount ``` ---- +For systems without a default web browser, the `Connect-AzAccount` command uses the device code authentication flow. The user can also force Azure PowerShell to use the device code flow rather than launching a browser by specifying the `UseDeviceAuthentication` argument. -## 4 - Implement DefaultAzureCredential in your application +```azurepowershell +Connect-AzAccount -UseDeviceAuthentication +``` + +--- [!INCLUDE [Implement DefaultAzureCredential](<../includes/implement-defaultazurecredential.md>)] diff --git a/docs/azure/sdk/includes/assign-local-dev-group-to-role-azure-portal-1.md b/docs/azure/sdk/includes/assign-local-dev-group-to-role-azure-portal-1.md deleted file mode 100644 index 03b2c85d78896..0000000000000 --- a/docs/azure/sdk/includes/assign-local-dev-group-to-role-azure-portal-1.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -ms.topic: include -ms.date: 07/31/2024 ---- -Locate the resource group for your app by searching for the resource group name using the search box at the top of the Azure portal. Navigate to your resource group by selecting the resource group name under the **Resource Groups** heading in the dialog box. diff --git a/docs/azure/sdk/includes/assign-local-dev-group-to-role-azure-portal-2.md b/docs/azure/sdk/includes/assign-local-dev-group-to-role-azure-portal-2.md deleted file mode 100644 index fcb0d9a2739d3..0000000000000 --- a/docs/azure/sdk/includes/assign-local-dev-group-to-role-azure-portal-2.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -ms.topic: include -ms.date: 07/31/2024 ---- -On the page for the resource group, select **Access control (IAM)** from the left-hand menu. diff --git a/docs/azure/sdk/includes/assign-local-dev-group-to-role-azure-portal-3.md b/docs/azure/sdk/includes/assign-local-dev-group-to-role-azure-portal-3.md deleted file mode 100644 index ac5932a711cc7..0000000000000 --- a/docs/azure/sdk/includes/assign-local-dev-group-to-role-azure-portal-3.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -ms.topic: include -ms.date: 07/31/2024 ---- -On the **Access control (IAM)** page: - -1. Select the **Role assignments** tab. -1. Select **+ Add** from the top menu and then **Add role assignment** from the resulting drop-down menu. diff --git a/docs/azure/sdk/includes/assign-local-dev-group-to-role-azure-portal-4.md b/docs/azure/sdk/includes/assign-local-dev-group-to-role-azure-portal-4.md deleted file mode 100644 index fc306be64a2ee..0000000000000 --- a/docs/azure/sdk/includes/assign-local-dev-group-to-role-azure-portal-4.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -ms.topic: include -ms.date: 07/31/2024 ---- -The **Add role assignment** page lists all of the roles that can be assigned for the resource group. - -1. Use the search box to filter the list to a more manageable size. This example shows how to filter for Storage Blob roles. -1. Select the role that you want to assign. - -Select **Next** to go to the next screen. diff --git a/docs/azure/sdk/includes/assign-local-dev-group-to-role-azure-portal-5.md b/docs/azure/sdk/includes/assign-local-dev-group-to-role-azure-portal-5.md deleted file mode 100644 index d313546178fc3..0000000000000 --- a/docs/azure/sdk/includes/assign-local-dev-group-to-role-azure-portal-5.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -ms.topic: include -ms.date: 07/31/2024 ---- -The next **Add role assignment** page allows you to specify what user to assign the role to. - -1. Select **User, group, or service principal** under **Assign access to**. -1. Select **+ Select members** under **Members**. - -A dialog box opens on the right-hand side of the Azure portal. diff --git a/docs/azure/sdk/includes/assign-local-dev-group-to-role-azure-portal-6.md b/docs/azure/sdk/includes/assign-local-dev-group-to-role-azure-portal-6.md deleted file mode 100644 index 954eca0be3077..0000000000000 --- a/docs/azure/sdk/includes/assign-local-dev-group-to-role-azure-portal-6.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -ms.topic: include -ms.date: 07/31/2024 ---- -In the **Select members** dialog: - -1. The **Select** text box can be used to filter the list of users and groups in your subscription. If needed, type the first few characters of the local development Microsoft Entra group you created for the app. -1. Select the local development Microsoft Entra group associated with your application. - -Select **Select** at the bottom of the dialog to continue. diff --git a/docs/azure/sdk/includes/assign-local-dev-group-to-role-azure-portal-7.md b/docs/azure/sdk/includes/assign-local-dev-group-to-role-azure-portal-7.md deleted file mode 100644 index 3252ed9cd52d5..0000000000000 --- a/docs/azure/sdk/includes/assign-local-dev-group-to-role-azure-portal-7.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -ms.topic: include -ms.date: 07/31/2024 ---- -The Microsoft Entra group shows as selected on the **Add role assignment** screen. Select **Review + assign** to go to the final page and then **Review + assign** again to complete the process. diff --git a/docs/azure/sdk/includes/assign-service-principal-to-role-azure-portal-1.md b/docs/azure/sdk/includes/assign-service-principal-to-role-azure-portal-1.md deleted file mode 100644 index 31cedf515a924..0000000000000 --- a/docs/azure/sdk/includes/assign-service-principal-to-role-azure-portal-1.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -ms.topic: include -ms.date: 08/02/2024 ---- -Locate the resource group for your app by searching for the resource group name using the search box at the top of the Azure portal.
-
-Navigate to your resource group by selecting the resource group name under the **Resource Groups** heading in the dialog box. diff --git a/docs/azure/sdk/includes/assign-service-principal-to-role-azure-portal-2.md b/docs/azure/sdk/includes/assign-service-principal-to-role-azure-portal-2.md deleted file mode 100644 index 7d2ab00bee47c..0000000000000 --- a/docs/azure/sdk/includes/assign-service-principal-to-role-azure-portal-2.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -ms.topic: include -ms.date: 08/02/2024 ---- -On the page for the resource group, select **Access control (IAM)** from the left-hand menu. diff --git a/docs/azure/sdk/includes/assign-service-principal-to-role-azure-portal-3.md b/docs/azure/sdk/includes/assign-service-principal-to-role-azure-portal-3.md deleted file mode 100644 index 83d0d8669fae0..0000000000000 --- a/docs/azure/sdk/includes/assign-service-principal-to-role-azure-portal-3.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -ms.topic: include -ms.date: 08/02/2024 ---- -On the **Access control (IAM)** page: - -1. Select the **Role assignments** tab. -1. Select **+ Add** from the top menu and then **Add role assignment** from the resulting drop-down menu. diff --git a/docs/azure/sdk/includes/assign-service-principal-to-role-azure-portal-4.md b/docs/azure/sdk/includes/assign-service-principal-to-role-azure-portal-4.md deleted file mode 100644 index 9c9edcf5b1e99..0000000000000 --- a/docs/azure/sdk/includes/assign-service-principal-to-role-azure-portal-4.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -ms.topic: include -ms.date: 08/02/2024 ---- -The **Add role assignment** page lists all of the roles that can be assigned for the resource group. - -1. Use the search box to filter the list to a more manageable size. This example shows how to filter for Storage Blob roles. -1. Select the role that you want to assign. - -Select **Next** to go to the next screen. diff --git a/docs/azure/sdk/includes/assign-service-principal-to-role-azure-portal-5.md b/docs/azure/sdk/includes/assign-service-principal-to-role-azure-portal-5.md deleted file mode 100644 index 81d5e0cb2a049..0000000000000 --- a/docs/azure/sdk/includes/assign-service-principal-to-role-azure-portal-5.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -ms.topic: include -ms.date: 08/02/2024 ---- -The next **Add role assignment** page allows you to specify what user to assign the role to. - -1. Select **User, group, or service principal** under **Assign access to**. -1. Select **+ Select members** under **Members**. - -A dialog box will open on the right-hand side of the Azure portal. diff --git a/docs/azure/sdk/includes/assign-service-principal-to-role-azure-portal-6.md b/docs/azure/sdk/includes/assign-service-principal-to-role-azure-portal-6.md deleted file mode 100644 index 9ad7f2272683f..0000000000000 --- a/docs/azure/sdk/includes/assign-service-principal-to-role-azure-portal-6.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -ms.topic: include -ms.date: 08/02/2024 ---- -In the **Select members** dialog: - -1. The **Select** text box can be used to filter the list of users and groups in your subscription. If needed, type the first few characters of the service principal you created for the app to filter the list. -1. Select the service principal associated with your application. - -Select **Select** at the bottom of the dialog to continue. diff --git a/docs/azure/sdk/includes/assign-service-principal-to-role-azure-portal-7.md b/docs/azure/sdk/includes/assign-service-principal-to-role-azure-portal-7.md deleted file mode 100644 index c533931fdcbf6..0000000000000 --- a/docs/azure/sdk/includes/assign-service-principal-to-role-azure-portal-7.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -ms.topic: include -ms.date: 08/02/2024 ---- -The service principal will now show as selected on the **Add role assignment** screen.
-
-Select **Review + assign** to go to the final page and then **Review + assign** again to complete the process. diff --git a/docs/azure/sdk/includes/implement-defaultazurecredential.md b/docs/azure/sdk/includes/implement-defaultazurecredential.md index 345527db4e502..dfe116a128eca 100644 --- a/docs/azure/sdk/includes/implement-defaultazurecredential.md +++ b/docs/azure/sdk/includes/implement-defaultazurecredential.md @@ -2,6 +2,13 @@ ms.topic: include ms.date: 08/15/2024 --- + +## Authenticate to Azure services from your app + +The [Azure Identity library](/dotnet/api/azure.identity?view=azure-dotnet&preserve-view=true) provides various *credentials*—implementations of `TokenCredential` adapted to supporting different scenarios and Microsoft Entra authentication flows. The steps ahead demonstrate how to use when working with user accounts locally. + +### Implement the code + [DefaultAzureCredential](../authentication/credential-chains.md#defaultazurecredential-overview) is an opinionated, ordered sequence of mechanisms for authenticating to Microsoft Entra ID. Each authentication mechanism is a class derived from the [TokenCredential](/dotnet/api/azure.core.tokencredential?view=azure-dotnet&preserve-view=true) class and is known as a *credential*. At runtime, `DefaultAzureCredential` attempts to authenticate using the first credential. If that credential fails to acquire an access token, the next credential in the sequence is attempted, and so on, until an access token is successfully obtained. In this way, your app can use different credentials in different environments without writing environment-specific code. To use `DefaultAzureCredential`, add the [Azure.Identity](/dotnet/api/azure.identity) and optionally the [Microsoft.Extensions.Azure](/dotnet/api/microsoft.extensions.azure) packages to your application: @@ -29,31 +36,8 @@ Azure services are accessed using specialized client classes from the various Az 1. Register the Azure service client using the corresponding `Add`-prefixed extension method. 1. Pass an instance of `DefaultAzureCredential` to the `UseCredential` method. -For example: - -```c# -using Microsoft.Extensions.Azure; -using Azure.Identity; - -builder.Services.AddAzureClients(clientBuilder => -{ - clientBuilder.AddBlobServiceClient( - new Uri("https://.blob.core.windows.net")); - clientBuilder.UseCredential(new DefaultAzureCredential()); -}); -``` - -An alternative to `UseCredential` is to instantiate `DefaultAzureCredential` directly: - -```c# -using Azure.Identity; - -builder.Services.AddSingleton(_ => - new BlobServiceClient( - new Uri("https://.blob.core.windows.net"), - new DefaultAzureCredential())); -``` +:::code language="csharp" source="../snippets/authentication/local-dev-account/Program.cs" id="snippet_DefaultAzureCredential_UseCredential"::: -When the preceding code runs on your local development workstation, it looks in the environment variables for an application service principal or at locally installed developer tools, such as Visual Studio, for a set of developer credentials. Either approach can be used to authenticate the app to Azure resources during local development. +An alternative to the `UseCredential` method is to provide the credential to the service client directly: -When deployed to Azure, this same code can also authenticate your app to other Azure resources. `DefaultAzureCredential` can retrieve environment settings and managed identity configurations to authenticate to other services automatically. +:::code language="csharp" source="../snippets/authentication/local-dev-account/Program.cs" id="snippet_DefaultAzureCredential"::: diff --git a/docs/azure/sdk/includes/local-dev-accounts-app-group-azure-portal-1.md b/docs/azure/sdk/includes/local-dev-accounts-app-group-azure-portal-1.md deleted file mode 100644 index d0ff152652c7c..0000000000000 --- a/docs/azure/sdk/includes/local-dev-accounts-app-group-azure-portal-1.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -ms.topic: include -ms.date: 07/31/2024 ---- -Navigate to the Microsoft Entra ID page in the Azure portal by typing *Microsoft Entra ID* into the search box at the top of the page. Select **Microsoft Entra ID** under the **Services** section. diff --git a/docs/azure/sdk/includes/local-dev-accounts-app-group-azure-portal-2.md b/docs/azure/sdk/includes/local-dev-accounts-app-group-azure-portal-2.md deleted file mode 100644 index 6b36e1108fbe4..0000000000000 --- a/docs/azure/sdk/includes/local-dev-accounts-app-group-azure-portal-2.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -ms.topic: include -ms.date: 07/31/2024 ---- -On the **Microsoft Entra ID** page, select **Groups** from the left-hand menu. diff --git a/docs/azure/sdk/includes/local-dev-accounts-app-group-azure-portal-3.md b/docs/azure/sdk/includes/local-dev-accounts-app-group-azure-portal-3.md deleted file mode 100644 index 8336209e8c76d..0000000000000 --- a/docs/azure/sdk/includes/local-dev-accounts-app-group-azure-portal-3.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -ms.topic: include -ms.date: 07/31/2024 ---- -On the **All groups** page, select **New group**. diff --git a/docs/azure/sdk/includes/local-dev-accounts-app-group-azure-portal-4.md b/docs/azure/sdk/includes/local-dev-accounts-app-group-azure-portal-4.md deleted file mode 100644 index abd253ab312cb..0000000000000 --- a/docs/azure/sdk/includes/local-dev-accounts-app-group-azure-portal-4.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -ms.topic: include -ms.date: 07/31/2024 ---- -On the **New Group** page: - -1. Select **Security** from the **Group type** drop-down. -1. **Group name** → A name for the security group, typically created from the application name. It's also helpful to include a string like *local-dev* in the name of the group to indicate the purpose of the group. -1. **Group description** → A description of the group's purpose. -1. Select the **No members selected** link under **Members** to add members to the group. diff --git a/docs/azure/sdk/includes/local-dev-accounts-app-group-azure-portal-5.md b/docs/azure/sdk/includes/local-dev-accounts-app-group-azure-portal-5.md deleted file mode 100644 index 30f61ecc73067..0000000000000 --- a/docs/azure/sdk/includes/local-dev-accounts-app-group-azure-portal-5.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -ms.topic: include -ms.date: 07/31/2024 ---- -On the **Add members** dialog box: - -1. Use the search box to filter the list of user names in the list. -1. Choose one or more users for local development for this app. As you choose an object, the object moves to the **Selected items** list at the bottom of the dialog. -1. When finished, choose the **Select** button. diff --git a/docs/azure/sdk/includes/local-dev-accounts-app-group-azure-portal-6.md b/docs/azure/sdk/includes/local-dev-accounts-app-group-azure-portal-6.md deleted file mode 100644 index ce2b3b41f47a3..0000000000000 --- a/docs/azure/sdk/includes/local-dev-accounts-app-group-azure-portal-6.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -ms.topic: include -ms.date: 07/31/2024 ---- -Back on the **New group** page, select **Create** to create the group. - -The group will be created and you will be taken back to the **All groups** page. It may take up to 30 seconds for the group to appear, and you may need to refresh the page due to caching in the Azure portal. diff --git a/docs/azure/sdk/includes/local-dev-app-ad-group-azure-portal-1.md b/docs/azure/sdk/includes/local-dev-app-ad-group-azure-portal-1.md deleted file mode 100644 index 3d821a0dba3b5..0000000000000 --- a/docs/azure/sdk/includes/local-dev-app-ad-group-azure-portal-1.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -ms.topic: include -ms.date: 08/05/2024 ---- -Navigate to the Microsoft Entra ID page in the Azure portal by typing *Microsoft Entra ID* into the search box at the top of the page. Select **Microsoft Entra ID** under the **Services** section. diff --git a/docs/azure/sdk/includes/local-dev-app-ad-group-azure-portal-2.md b/docs/azure/sdk/includes/local-dev-app-ad-group-azure-portal-2.md deleted file mode 100644 index 85eeee5e7b294..0000000000000 --- a/docs/azure/sdk/includes/local-dev-app-ad-group-azure-portal-2.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -ms.topic: include -ms.date: 08/05/2024 ---- -On the **Microsoft Entra ID** page, select **Groups** from the left-hand menu. diff --git a/docs/azure/sdk/includes/local-dev-app-ad-group-azure-portal-3.md b/docs/azure/sdk/includes/local-dev-app-ad-group-azure-portal-3.md deleted file mode 100644 index 6e76326757e72..0000000000000 --- a/docs/azure/sdk/includes/local-dev-app-ad-group-azure-portal-3.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -ms.topic: include -ms.date: 08/05/2024 ---- -On the **All groups** page, select **New group**. diff --git a/docs/azure/sdk/includes/local-dev-app-ad-group-azure-portal-4.md b/docs/azure/sdk/includes/local-dev-app-ad-group-azure-portal-4.md deleted file mode 100644 index 2750c61297251..0000000000000 --- a/docs/azure/sdk/includes/local-dev-app-ad-group-azure-portal-4.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -ms.topic: include -ms.date: 08/05/2024 ---- -On the **New Group** page: - -1. **Group type** → **Security** -1. **Group name** → A name for the security group, typically created from the application name. It's also helpful to include a string like *local-dev* in the name of the group to indicate the purpose of the group. -1. **Group description** → A description of the purpose of the group. -1. Select the **No members selected** link under **Members** to add members to the group. diff --git a/docs/azure/sdk/includes/local-dev-app-ad-group-azure-portal-5.md b/docs/azure/sdk/includes/local-dev-app-ad-group-azure-portal-5.md deleted file mode 100644 index b330f7ea258fa..0000000000000 --- a/docs/azure/sdk/includes/local-dev-app-ad-group-azure-portal-5.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -ms.topic: include -ms.date: 08/05/2024 ---- -On the **Add members** dialog box: - -1. Use the search box to filter the list of principal names in the list. -1. Select the application service principals for local development for this app. As objects are selected, they'll be greyed out and move to the **Selected items** list at the bottom of the dialog. -1. When finished, select the **Select** button. diff --git a/docs/azure/sdk/includes/local-dev-app-ad-group-azure-portal-6.md b/docs/azure/sdk/includes/local-dev-app-ad-group-azure-portal-6.md deleted file mode 100644 index 2fd855f5551e1..0000000000000 --- a/docs/azure/sdk/includes/local-dev-app-ad-group-azure-portal-6.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -ms.topic: include -ms.date: 08/05/2024 ---- -Back on the **New group** page, select **Create** to create the group.
-
-The group will be created and you'll be taken back to the **All groups** page. It may take up to 30 seconds for the group to appear. You may need to refresh the page due to caching in the Azure portal. diff --git a/docs/azure/sdk/includes/on-premises-app-registration-azure-portal-1.md b/docs/azure/sdk/includes/on-premises-app-registration-azure-portal-1.md deleted file mode 100644 index cfd1d0d543512..0000000000000 --- a/docs/azure/sdk/includes/on-premises-app-registration-azure-portal-1.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -ms.topic: include -ms.date: 08/02/2024 ---- -In the Azure portal: - -1. Enter *app registrations* in the search bar at the top of the Azure portal. -1. Select the item labeled **App registrations** under the under **Services** heading on the menu that appears below the search bar. diff --git a/docs/azure/sdk/includes/on-premises-app-registration-azure-portal-2.md b/docs/azure/sdk/includes/on-premises-app-registration-azure-portal-2.md deleted file mode 100644 index 18eb3060d579d..0000000000000 --- a/docs/azure/sdk/includes/on-premises-app-registration-azure-portal-2.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -ms.topic: include -ms.date: 08/02/2024 ---- -On the **App registrations** page, select **+ New registration**. diff --git a/docs/azure/sdk/includes/on-premises-app-registration-azure-portal-3.md b/docs/azure/sdk/includes/on-premises-app-registration-azure-portal-3.md deleted file mode 100644 index c366946364325..0000000000000 --- a/docs/azure/sdk/includes/on-premises-app-registration-azure-portal-3.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -ms.topic: include -ms.date: 08/02/2024 ---- -On the **Register an application** page, fill out the form as follows: - -1. **Name** → Enter a name for the app registration in Azure. It's recommended this name include the app name and environment (test, prod) the app registration is for. -1. **Supported account types** → *Accounts in this organizational directory only*. - -Select **Register** to register your app and create the application service principal. diff --git a/docs/azure/sdk/includes/on-premises-app-registration-azure-portal-4.md b/docs/azure/sdk/includes/on-premises-app-registration-azure-portal-4.md deleted file mode 100644 index 87c42c94db6df..0000000000000 --- a/docs/azure/sdk/includes/on-premises-app-registration-azure-portal-4.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -ms.topic: include -ms.date: 08/02/2024 ---- -On the App registration page for your app: - -1. **Application (client) ID** → This is the app id the app will use to access Azure during local development. Copy this value to a temporary location in a text editor as you will need it in a future step. -1. **Directory (tenant) id** → This value will also be needed by your app when it authenticates to Azure. Copy this value to a temporary location in a text editor it will also be needed it in a future step. -1. **Client credentials** → You must set the client credentials for the app before your app can authenticate to Azure and use Azure services. Select **Add a certificate or secret** to add credentials for your app. diff --git a/docs/azure/sdk/includes/on-premises-app-registration-azure-portal-5.md b/docs/azure/sdk/includes/on-premises-app-registration-azure-portal-5.md deleted file mode 100644 index a61dcf4bf5c9e..0000000000000 --- a/docs/azure/sdk/includes/on-premises-app-registration-azure-portal-5.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -ms.topic: include -ms.date: 08/02/2024 ---- -On the **Certificates & secrets** page, select **+ New client secret**. diff --git a/docs/azure/sdk/includes/on-premises-app-registration-azure-portal-6.md b/docs/azure/sdk/includes/on-premises-app-registration-azure-portal-6.md deleted file mode 100644 index ad1fc5e3b486a..0000000000000 --- a/docs/azure/sdk/includes/on-premises-app-registration-azure-portal-6.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -ms.topic: include -ms.date: 08/02/2024 ---- -The **Add a client secret** dialog will pop out from the right-hand side of the page. In this dialog: - -1. **Description** → Enter a value of *Current*. -1. **Expires** → Select a value of *24 months*. - -Select **Add** to add the secret.
-
-***IMPORTANT: Set a reminder in your calendar prior to the expiration date of the secret.*** This way, you can add a new secret prior and update your apps prior to the expiration of this secret and avoid a service interruption in your app. diff --git a/docs/azure/sdk/includes/on-premises-app-registration-azure-portal-7.md b/docs/azure/sdk/includes/on-premises-app-registration-azure-portal-7.md deleted file mode 100644 index a126d22ec84bc..0000000000000 --- a/docs/azure/sdk/includes/on-premises-app-registration-azure-portal-7.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -ms.topic: include -ms.date: 08/02/2024 ---- -On the **Certificates & secrets** page, you will be shown the value of the client secret.
-
-Copy this value to a temporary location in a text editor, as you'll need it in a future step.
-
-***IMPORTANT: This is the only time you will see this value.*** Once you leave or refresh this page, you won't be able to see this value again. You may add an additional client secret without invalidating this client secret, but you won't see this value again. diff --git a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-1-240px.png b/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-1-240px.png deleted file mode 100644 index 61b981b817914..0000000000000 Binary files a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-1-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-1.png b/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-1.png deleted file mode 100644 index 238dc0318a657..0000000000000 Binary files a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-1.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-2-240px.png b/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-2-240px.png deleted file mode 100644 index 0f9348412e976..0000000000000 Binary files a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-2-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-2.png b/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-2.png deleted file mode 100644 index e25995911b936..0000000000000 Binary files a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-2.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-3-240px.png b/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-3-240px.png deleted file mode 100644 index 9b0ba5c2a21b5..0000000000000 Binary files a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-3-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-3.png b/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-3.png deleted file mode 100644 index c925c49571913..0000000000000 Binary files a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-3.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-4-240px.png b/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-4-240px.png deleted file mode 100644 index f27e3d8ca5b46..0000000000000 Binary files a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-4-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-4.png b/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-4.png deleted file mode 100644 index d32af017b7b28..0000000000000 Binary files a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-4.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-5-240px.png b/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-5-240px.png deleted file mode 100644 index 190c9c7c8e02e..0000000000000 Binary files a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-5-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-5.png b/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-5.png deleted file mode 100644 index edcf681014e13..0000000000000 Binary files a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-5.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-6-240px.png b/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-6-240px.png deleted file mode 100644 index b76ae12713896..0000000000000 Binary files a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-6-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-6.png b/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-6.png deleted file mode 100644 index fb77ded6488e9..0000000000000 Binary files a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-6.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-7-240px.png b/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-7-240px.png deleted file mode 100644 index 77a376167bff5..0000000000000 Binary files a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-7-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-7.png b/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-7.png deleted file mode 100644 index 6051efea2f35a..0000000000000 Binary files a/docs/azure/sdk/media/assign-local-dev-group-to-role-azure-portal-7.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-1-240px.png b/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-1-240px.png deleted file mode 100644 index 6b1b2baee004f..0000000000000 Binary files a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-1-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-1.png b/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-1.png deleted file mode 100644 index 0f0b2bbb15f43..0000000000000 Binary files a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-1.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-2-240px.png b/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-2-240px.png deleted file mode 100644 index 2a097242682b9..0000000000000 Binary files a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-2-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-2.png b/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-2.png deleted file mode 100644 index 791e417fb4da8..0000000000000 Binary files a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-2.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-3-240px.png b/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-3-240px.png deleted file mode 100644 index 42ad6518d65d5..0000000000000 Binary files a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-3-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-3.png b/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-3.png deleted file mode 100644 index 1c6377e21494f..0000000000000 Binary files a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-3.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-4-240px.png b/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-4-240px.png deleted file mode 100644 index a68fd46043a31..0000000000000 Binary files a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-4-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-4.png b/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-4.png deleted file mode 100644 index 49c2a2cacbefd..0000000000000 Binary files a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-4.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-5-240px.png b/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-5-240px.png deleted file mode 100644 index 000df599c6515..0000000000000 Binary files a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-5-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-5.png b/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-5.png deleted file mode 100644 index 1b42b0b92f638..0000000000000 Binary files a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-5.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-6-240px.png b/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-6-240px.png deleted file mode 100644 index ea11b0c2f70a7..0000000000000 Binary files a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-6-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-6.png b/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-6.png deleted file mode 100644 index 8c49eae27fd5e..0000000000000 Binary files a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-6.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-7-240px.png b/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-7-240px.png deleted file mode 100644 index 216b4b7159b30..0000000000000 Binary files a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-7-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-7.png b/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-7.png deleted file mode 100644 index c23328681d224..0000000000000 Binary files a/docs/azure/sdk/media/assign-service-principal-to-role-azure-portal-7.png and /dev/null differ diff --git a/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-1-240px.png b/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-1-240px.png deleted file mode 100644 index a88b2c98066c1..0000000000000 Binary files a/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-1-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-1.png b/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-1.png deleted file mode 100644 index a3c83ceb03c33..0000000000000 Binary files a/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-1.png and /dev/null differ diff --git a/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-2-240px.png b/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-2-240px.png deleted file mode 100644 index b2902fe09cf23..0000000000000 Binary files a/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-2-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-2.png b/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-2.png deleted file mode 100644 index d870b4dfa4d45..0000000000000 Binary files a/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-2.png and /dev/null differ diff --git a/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-3-240px.png b/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-3-240px.png deleted file mode 100644 index 8de9242a1d4dc..0000000000000 Binary files a/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-3-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-3.png b/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-3.png deleted file mode 100644 index 18340291cd839..0000000000000 Binary files a/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-3.png and /dev/null differ diff --git a/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-4-240px.png b/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-4-240px.png deleted file mode 100644 index 48ac84c56d2c5..0000000000000 Binary files a/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-4-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-4.png b/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-4.png deleted file mode 100644 index 417ff454e6a5c..0000000000000 Binary files a/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-4.png and /dev/null differ diff --git a/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-5-240px.png b/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-5-240px.png deleted file mode 100644 index 90450ead4c867..0000000000000 Binary files a/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-5-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-5.png b/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-5.png deleted file mode 100644 index 450ce3d51a49a..0000000000000 Binary files a/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-5.png and /dev/null differ diff --git a/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-6-240px.png b/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-6-240px.png deleted file mode 100644 index 57be7c6822a9d..0000000000000 Binary files a/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-6-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-6.png b/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-6.png deleted file mode 100644 index 3e97529112635..0000000000000 Binary files a/docs/azure/sdk/media/local-dev-accounts-app-group-azure-portal-6.png and /dev/null differ diff --git a/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-1-240px.png b/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-1-240px.png deleted file mode 100644 index 2d60bde983983..0000000000000 Binary files a/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-1-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-1.png b/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-1.png deleted file mode 100644 index 7b58da8fdce40..0000000000000 Binary files a/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-1.png and /dev/null differ diff --git a/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-2-240px.png b/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-2-240px.png deleted file mode 100644 index 958fcffa8d8c5..0000000000000 Binary files a/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-2-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-2.png b/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-2.png deleted file mode 100644 index f429261c5e103..0000000000000 Binary files a/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-2.png and /dev/null differ diff --git a/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-3-240px.png b/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-3-240px.png deleted file mode 100644 index 47342477f6bf0..0000000000000 Binary files a/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-3-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-3.png b/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-3.png deleted file mode 100644 index 75816e304d1fc..0000000000000 Binary files a/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-3.png and /dev/null differ diff --git a/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-4-240px.png b/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-4-240px.png deleted file mode 100644 index 331065c228a95..0000000000000 Binary files a/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-4-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-4.png b/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-4.png deleted file mode 100644 index fffebda95dc2b..0000000000000 Binary files a/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-4.png and /dev/null differ diff --git a/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-5-240px.png b/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-5-240px.png deleted file mode 100644 index d3b0d693ebb09..0000000000000 Binary files a/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-5-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-5.png b/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-5.png deleted file mode 100644 index 0811978d13c82..0000000000000 Binary files a/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-5.png and /dev/null differ diff --git a/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-6-240px.png b/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-6-240px.png deleted file mode 100644 index 57be28bea9c89..0000000000000 Binary files a/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-6-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-6.png b/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-6.png deleted file mode 100644 index fb53294d7ab38..0000000000000 Binary files a/docs/azure/sdk/media/local-dev-app-ad-group-azure-portal-6.png and /dev/null differ diff --git a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-1-240px.png b/docs/azure/sdk/media/on-premises-app-registration-azure-portal-1-240px.png deleted file mode 100644 index 2e974fd6e139c..0000000000000 Binary files a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-1-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-1.png b/docs/azure/sdk/media/on-premises-app-registration-azure-portal-1.png deleted file mode 100644 index 0ac4ac315ce40..0000000000000 Binary files a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-1.png and /dev/null differ diff --git a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-2-240px.png b/docs/azure/sdk/media/on-premises-app-registration-azure-portal-2-240px.png deleted file mode 100644 index 2eb02abc15181..0000000000000 Binary files a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-2-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-2.png b/docs/azure/sdk/media/on-premises-app-registration-azure-portal-2.png deleted file mode 100644 index 1e3142820baa8..0000000000000 Binary files a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-2.png and /dev/null differ diff --git a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-3-240px.png b/docs/azure/sdk/media/on-premises-app-registration-azure-portal-3-240px.png deleted file mode 100644 index 6de6e8870a9ca..0000000000000 Binary files a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-3-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-3.png b/docs/azure/sdk/media/on-premises-app-registration-azure-portal-3.png deleted file mode 100644 index b2e1f22d41571..0000000000000 Binary files a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-3.png and /dev/null differ diff --git a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-4-240px.png b/docs/azure/sdk/media/on-premises-app-registration-azure-portal-4-240px.png deleted file mode 100644 index e4629a43dd03f..0000000000000 Binary files a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-4-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-4.png b/docs/azure/sdk/media/on-premises-app-registration-azure-portal-4.png deleted file mode 100644 index 9c6f485b963b0..0000000000000 Binary files a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-4.png and /dev/null differ diff --git a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-5-240px.png b/docs/azure/sdk/media/on-premises-app-registration-azure-portal-5-240px.png deleted file mode 100644 index 9af2c7e87f2f9..0000000000000 Binary files a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-5-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-5.png b/docs/azure/sdk/media/on-premises-app-registration-azure-portal-5.png deleted file mode 100644 index b1d1d36bebfbd..0000000000000 Binary files a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-5.png and /dev/null differ diff --git a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-6-240px.png b/docs/azure/sdk/media/on-premises-app-registration-azure-portal-6-240px.png deleted file mode 100644 index 7db46a5243921..0000000000000 Binary files a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-6-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-6.png b/docs/azure/sdk/media/on-premises-app-registration-azure-portal-6.png deleted file mode 100644 index 69e983411c4ed..0000000000000 Binary files a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-6.png and /dev/null differ diff --git a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-7-240px.png b/docs/azure/sdk/media/on-premises-app-registration-azure-portal-7-240px.png deleted file mode 100644 index 7dc0669556afb..0000000000000 Binary files a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-7-240px.png and /dev/null differ diff --git a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-7.png b/docs/azure/sdk/media/on-premises-app-registration-azure-portal-7.png deleted file mode 100644 index 9280412205c06..0000000000000 Binary files a/docs/azure/sdk/media/on-premises-app-registration-azure-portal-7.png and /dev/null differ diff --git a/docs/azure/sdk/snippets/authentication/additional-auth/username-password/Program.cs b/docs/azure/sdk/snippets/authentication/additional-auth/username-password/Program.cs deleted file mode 100644 index d4bed3795f628..0000000000000 --- a/docs/azure/sdk/snippets/authentication/additional-auth/username-password/Program.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Azure.Identity; -using Azure.Storage.Blobs; -using Azure.Storage.Blobs.Models; - -string clientId = Environment.GetEnvironmentVariable("AZURE_CLIENT_ID")!; -string tenantId = Environment.GetEnvironmentVariable("AZURE_TENANT_ID")!; -string username = Environment.GetEnvironmentVariable("AZURE_USERNAME")!; -string password = Environment.GetEnvironmentVariable("AZURE_PASSWORD")!; - -BlobServiceClient client = new( - new Uri("https://.blob.core.windows.net"), - new UsernamePasswordCredential(username, password, tenantId, clientId)); - -foreach (BlobContainerItem blobItem in client.GetBlobContainers()) -{ - Console.WriteLine(blobItem.Name); -} diff --git a/docs/azure/sdk/snippets/authentication/local-dev-account/Program.cs b/docs/azure/sdk/snippets/authentication/local-dev-account/Program.cs new file mode 100644 index 0000000000000..b09ccffb4e6aa --- /dev/null +++ b/docs/azure/sdk/snippets/authentication/local-dev-account/Program.cs @@ -0,0 +1,69 @@ +using Azure.Identity; +using Microsoft.Extensions.Azure; +using Azure.Storage.Blobs; +using Azure.Core; + +var builder = WebApplication.CreateBuilder(args); + +registerUsingServicePrincipal(builder); + +var app = builder.Build(); + +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseHttpsRedirection(); + +var summaries = new[] +{ + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" +}; + +app.MapGet("/weatherforecast", async (BlobServiceClient client) => +{ + var containerClient = client.GetBlobContainerClient("docs"); + + var blobs = containerClient.GetBlobs(); + + var forecast = Enumerable.Range(1, 5).Select(index => + new WeatherForecast + ( + DateOnly.FromDateTime(DateTime.Now.AddDays(index)), + Random.Shared.Next(-20, 55), + summaries[Random.Shared.Next(summaries.Length)] + )) + .ToArray(); + return blobs.FirstOrDefault().Name; +}) +.WithName("GetWeatherForecast") +.WithOpenApi(); + +app.Run(); + +void registerUsingServicePrincipal(WebApplicationBuilder builder) +{ + #region snippet_DefaultAzureCredential_UseCredential + builder.Services.AddAzureClients(clientBuilder => + { + clientBuilder.AddBlobServiceClient( + new Uri("https://.blob.core.windows.net")); + + clientBuilder.UseCredential(new DefaultAzureCredential()); + }); + #endregion snippet_DefaultAzureCredential_UseCredential + + #region snippet_DefaultAzureCredential + builder.Services.AddSingleton(_ => + new BlobServiceClient( + new Uri("https://.blob.core.windows.net"), + new DefaultAzureCredential())); + #endregion snippet_DefaultAzureCredential +} + +internal record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) +{ + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); +} diff --git a/docs/azure/sdk/snippets/authentication/local-dev-account/Properties/launchSettings.json b/docs/azure/sdk/snippets/authentication/local-dev-account/Properties/launchSettings.json new file mode 100644 index 0000000000000..02561bcc4467b --- /dev/null +++ b/docs/azure/sdk/snippets/authentication/local-dev-account/Properties/launchSettings.json @@ -0,0 +1,15 @@ +{ + "profiles": { + "UserAssignedIdentityClientId": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:52833;http://localhost:52834", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/docs/azure/sdk/snippets/authentication/additional-auth/username-password/UsernamePassword.csproj b/docs/azure/sdk/snippets/authentication/local-dev-account/UserAssignedIdentityClientId.csproj similarity index 58% rename from docs/azure/sdk/snippets/authentication/additional-auth/username-password/UsernamePassword.csproj rename to docs/azure/sdk/snippets/authentication/local-dev-account/UserAssignedIdentityClientId.csproj index 0b365c0f6639f..94c4ea943ef74 100644 --- a/docs/azure/sdk/snippets/authentication/additional-auth/username-password/UsernamePassword.csproj +++ b/docs/azure/sdk/snippets/authentication/local-dev-account/UserAssignedIdentityClientId.csproj @@ -1,15 +1,17 @@ - + - Exe net9.0 - enable enable + enable + + + diff --git a/docs/azure/sdk/snippets/authentication/local-dev-account/appsettings.Development.json b/docs/azure/sdk/snippets/authentication/local-dev-account/appsettings.Development.json new file mode 100644 index 0000000000000..0c208ae9181e5 --- /dev/null +++ b/docs/azure/sdk/snippets/authentication/local-dev-account/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/docs/azure/sdk/snippets/authentication/local-dev-account/appsettings.json b/docs/azure/sdk/snippets/authentication/local-dev-account/appsettings.json new file mode 100644 index 0000000000000..10f68b8c8b4f7 --- /dev/null +++ b/docs/azure/sdk/snippets/authentication/local-dev-account/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/docs/csharp/event-pattern.md b/docs/csharp/event-pattern.md index 5e88b53485b65..0116f1326c01a 100644 --- a/docs/csharp/event-pattern.md +++ b/docs/csharp/event-pattern.md @@ -22,9 +22,9 @@ void EventRaised(object sender, EventArgs args); This standard signature provides insight into when events are used: -- ***The return type is void***. Events may have zero to many listeners. Raising an event notifies all listeners. In general, listeners don't provide values in response to events. +- ***The return type is void***. Events can have zero to many listeners. Raising an event notifies all listeners. In general, listeners don't provide values in response to events. - ***Events indicate the sender***: The event signature includes the object that raised the event. That provides any listener with a mechanism to communicate with the sender. The compile-time type of `sender` is `System.Object`, even though you likely know a more derived type that would always be correct. By convention, use `object`. -- ***Events package additional information in a single structure***: The `args` parameter is a type derived from that includes any additional necessary information. (You'll see in the [next section](modern-events.md) that this convention is no longer enforced.) If your event type doesn't need any more arguments, you still must provide both arguments. There's a special value, that you should use to denote that your event doesn't contain any additional information. +- ***Events package more information in a single structure***: The `args` parameter is a type derived from that includes any more necessary information. (You'll see in the [next section](modern-events.md) that this convention is no longer enforced.) If your event type doesn't need any more arguments, you still must provide both arguments. There's a special value, that you should use to denote that your event doesn't contain any additional information. Let's build a class that lists files in a directory, or any of its subdirectories that follow a pattern. This component raises an event for each file found that matches the pattern. @@ -48,22 +48,21 @@ The simplest way to add an event to your class is to declare that event as a pub :::code language="csharp" source="./snippets/events/Program.cs" id="DeclareEvent"::: -This looks like it's declaring a public field, which would appear to be a bad object-oriented practice. You want to protect data access through properties, or methods. While this code might look like a bad practice, the code generated by the compiler does create wrappers so that the event objects can only be accessed in safe ways. The only operations available on a field-like event are *add handler*: +This looks like it's declaring a public field, which would appear to be a bad object-oriented practice. You want to protect data access through properties, or methods. While this code might look like a bad practice, the code generated by the compiler does create wrappers so that the event objects can only be accessed in safe ways. The only operations available on a field-like event are *add* and *remove* handler: :::code language="csharp" source="./snippets/events/Program.cs" id="AttachEventHandler"::: -And *remove handler*: - :::code language="csharp" source="./snippets/events/Program.cs" id="DetachHandler"::: -There's a local variable for the handler. If you used the body of the lambda, the remove wouldn't work correctly. It would be a different instance of the delegate, and silently do nothing. +There's a local variable for the handler. If you used the body of the lambda, the `remove` handler wouldn't work correctly. It would be a different instance of the delegate, and silently do nothing. Code outside the class can't raise the event, nor can it perform any other operations. +Beginning with C# 14, events can be declared as [partial members](./language-reference/keywords/partial-member.md). A partial event declaration must include a *defining declaration* and an *implementing declaration*. The defining declaration must use the field-like event syntax. The implementing declaration must declare the `add` and `remove` handlers. + ## Return values from event subscribers -Your simple version is working fine. Let's add another feature: -Cancellation. +Your simple version is working fine. Let's add another feature: Cancellation. When you raise the *Found* event, listeners should be able to stop further processing, if this file is the last one sought. diff --git a/docs/csharp/language-reference/keywords/add.md b/docs/csharp/language-reference/keywords/add.md index 915a3aa8ce8ec..8c30022d01000 100644 --- a/docs/csharp/language-reference/keywords/add.md +++ b/docs/csharp/language-reference/keywords/add.md @@ -1,25 +1,22 @@ --- -description: Learn how to create custom event accessors using add keyword in C# -title: "add keyword" -ms.date: 07/20/2015 +description: The `add` contextual keyword declares an event accessor that adds a handler to that event. +title: "The `add` keyword" +ms.date: 03/13/2025 f1_keywords: - "add_CSharpKeyword" helpviewer_keywords: - "add event accessor [C#]" -ms.assetid: faf30b99-10e8-45cd-ab9a-57585d4d1d8d --- -# add (C# Reference) +# The `add` contextual keyword (C# Reference) -The `add` contextual keyword is used to define a custom event accessor that is invoked when client code subscribes to your [event](./event.md). If you supply a custom `add` accessor, you must also supply a [remove](./remove.md) accessor. - -## Example +The `add` contextual keyword is used to define a custom event accessor that is invoked when client code subscribes to your [event](./event.md). If you supply a custom `add` accessor, you must also supply a [remove](./remove.md) accessor. The following example shows an event that has custom `add` and [remove](./remove.md) accessors. For the full example, see [How to implement interface events](../../programming-guide/events/how-to-implement-interface-events.md). - -[!code-csharp[csrefKeywordsContextual#15](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsContextual/CS/csrefKeywordsContextual.cs#15)] - - You do not typically need to provide your own custom event accessors. The accessors that are automatically generated by the compiler when you declare an event are sufficient for most scenarios. - + +:::code language="csharp" source="./snippets/events.cs" id="AddHandler"::: + +You don't typically need to provide your own custom event accessors. The automatically generated accessors when you declare an event are sufficient for most scenarios. Beginning with C# 14, you can declare [`partial`](./partial-member.md) events. The implementing declaration of a partial event must declare the `add` and `remove` handlers. + ## See also - [Events](../../programming-guide/events/index.md) diff --git a/docs/csharp/language-reference/keywords/event.md b/docs/csharp/language-reference/keywords/event.md index 702560cc1888c..f0d6f77815670 100644 --- a/docs/csharp/language-reference/keywords/event.md +++ b/docs/csharp/language-reference/keywords/event.md @@ -1,7 +1,7 @@ --- -description: "event - C# Reference" -title: "event keyword" -ms.date: 07/20/2015 +description: "Learn how to declare events with the `event` keyword - C# Reference" +title: "The `event` keyword" +ms.date: 03/13/2025 f1_keywords: - "event" - "remove" @@ -9,36 +9,35 @@ f1_keywords: - "add" helpviewer_keywords: - "event keyword [C#]" -ms.assetid: 7858fd85-153b-4259-85d0-6aa13c35f174 --- -# event (C# reference) +# The `event` keyword (C# reference) An ***event*** is a member that enables an object to trigger notifications. Event users can attach executable code for events by supplying ***event handlers***. The `event` keyword declares an ***event***. The event is of a delegate type. While an object triggers an event, the event invokes all supplied event handlers. Event handlers are delegate instances added to the event and executed when the event is raised. Event users can add or remove their event handlers on an event. -## Example +The following example shows how to declare and raise an event that uses as the underlying delegate type. For the complete code example, see [How to publish events that conform to .NET Guidelines](/dotnet/standard/events). That sample demonstrates the generic delegate type, how to subscribe to an event, and create an event handler method, -The following example shows how to declare and raise an event that uses as the underlying delegate type. For the complete code example that also shows how to use the generic delegate type and how to subscribe to an event and create an event handler method, see [How to publish events that conform to .NET Guidelines](/dotnet/standard/events). +:::code language="csharp" source="./snippets/Events.cs" id="EventExample"::: -[!code-csharp[csrefKeywordsModifiers#7](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsModifiers/CS/csrefKeywordsModifiers.cs#7)] +Events are multicast delegates that can only be invoked from within the class (or derived classes) or struct where they're declared (the publisher class). If other classes or structs subscribe to the event, their event handler methods are called when the publisher class raises the event. For more information and code examples, see [Events](../../programming-guide/events/index.md) and [Delegates](../../programming-guide/delegates/index.md). -Events are a special kind of multicast delegate that can only be invoked from within the class (or derived classes) or struct where they are declared (the publisher class). If other classes or structs subscribe to the event, their event handler methods will be called when the publisher class raises the event. For more information and code examples, see [Events](../../programming-guide/events/index.md) and [Delegates](../../programming-guide/delegates/index.md). +Events can be marked as [`public`](./public.md), [`private`](./private.md), [`protected`](./protected.md), [`internal`](./internal.md), [`protected internal`](./protected-internal.md), or [`private protected`](./private-protected.md). These access modifiers define how users of the class can access the event. For more information, see [Access Modifiers](../../programming-guide/classes-and-structs/access-modifiers.md). -Events can be marked as [public](./public.md), [private](./private.md), [protected](./protected.md), [internal](./internal.md), [protected internal](./protected-internal.md), or [private protected](./private-protected.md). These access modifiers define how users of the class can access the event. For more information, see [Access Modifiers](../../programming-guide/classes-and-structs/access-modifiers.md). +Beginning with C# 14, events can be [`partial`](./partial-member.md). Partial events have one defining declaration and one implementing declaration. The defining declaration must use the field-like syntax. The implementing declaration must declare the `add` and `remove` handlers. ## Keywords and events The following keywords apply to events. -|Keyword|Description|For more information| -|-------------|-----------------|--------------------------| -|[static](./static.md)|Makes the event available to callers at any time, even if no instance of the class exists.|[Static Classes and Static Class Members](../../programming-guide/classes-and-structs/static-classes-and-static-class-members.md)| -|[virtual](./virtual.md)|Allows derived classes to override the event behavior by using the [override](./override.md) keyword.|[Inheritance](../../fundamentals/object-oriented/inheritance.md)| -|[sealed](./sealed.md)|Specifies that for derived classes it is no longer virtual.|| -|[abstract](./abstract.md)|The compiler will not generate the `add` and `remove` event accessor blocks and therefore derived classes must provide their own implementation.|| +| Keyword | Description | For more information | +|---------------------------|-----------------|----------------------| +| [`static`](./static.md) | Makes the event available to callers at any time, even if no instance of the class exists. | [Static Classes and Static Class Members](../../programming-guide/classes-and-structs/static-classes-and-static-class-members.md) | +| [`virtual`](./virtual.md) | Allows derived classes to override the event behavior by using the [override](./override.md) keyword. | [Inheritance](../../fundamentals/object-oriented/inheritance.md)| +| [`sealed`](./sealed.md) | Specifies that for derived classes it's no longer virtual. | | +| [`abstract`](./abstract.md) | The compiler doesn't generate the `add` and `remove` event accessor blocks and therefore derived classes must provide their own implementation. | | -An event may be declared as a static event by using the [static](./static.md) keyword. This makes the event available to callers at any time, even if no instance of the class exists. For more information, see [Static Classes and Static Class Members](../../programming-guide/classes-and-structs/static-classes-and-static-class-members.md). +An event can be declared as a static event by using the [static](./static.md) keyword. Static events are available to callers at any time, even if no instance of the class exists. For more information, see [Static Classes and Static Class Members](../../programming-guide/classes-and-structs/static-classes-and-static-class-members.md). -An event can be marked as a virtual event by using the [virtual](./virtual.md) keyword. This enables derived classes to override the event behavior by using the [override](./override.md) keyword. For more information, see [Inheritance](../../fundamentals/object-oriented/inheritance.md). An event overriding a virtual event can also be [sealed](./sealed.md), which specifies that for derived classes it is no longer virtual. Lastly, an event can be declared [abstract](./abstract.md), which means that the compiler will not generate the `add` and `remove` event accessor blocks. Therefore derived classes must provide their own implementation. +An event can be marked as a virtual event by using the [`virtual`](./virtual.md) keyword. Derived classes can override the event behavior by using the [`override`](./override.md) keyword. For more information, see [Inheritance](../../fundamentals/object-oriented/inheritance.md). An event overriding a virtual event can also be [`sealed`](./sealed.md), which specifies that for derived classes it's no longer virtual. Lastly, an event can be declared [`abstract`](./abstract.md), which means that the compiler doesn't generate the `add` and `remove` event accessor blocks. Therefore derived classes must provide their own implementation. ## C# language specification diff --git a/docs/csharp/language-reference/keywords/partial-member.md b/docs/csharp/language-reference/keywords/partial-member.md index 2d9a607039824..7556ca6e8ada7 100644 --- a/docs/csharp/language-reference/keywords/partial-member.md +++ b/docs/csharp/language-reference/keywords/partial-member.md @@ -1,7 +1,7 @@ --- description: "Partial members are members that can be declared in one partial type declaration and defined in a separate partial type declaration." title: "Partial members" -ms.date: 08/15/2024 +ms.date: 03/13/2025 f1_keywords: - "partialmethod_CSharpKeyword" helpviewer_keywords: @@ -9,12 +9,12 @@ helpviewer_keywords: --- # Partial member (C# Reference) -A partial member has one *declaring declaration* and often one *implementing declaration*. The *declaring declaration* doesn't include a body. The *implementing declaration* provides the body of the member. Partial members enable class designers to provide member hooks that can be implemented by tooling such as source generators. Partial types and members provide a way for human developers to write part of a type while tools write other parts of the type. If the developer doesn't supply an optional implementing declaration, the compiler can remove the declaring declaration at compile time. The following conditions apply to partial members: +A partial member has one *declaring declaration* and often one *implementing declaration*. The *declaring declaration* doesn't include a body. The *implementing declaration* provides the body of the member. Partial members enable class designers to provide member hooks for tooling such as source generators to implement. Partial types and members provide a way for human developers to write part of a type while tools write other parts of the type. If the developer doesn't supply an optional implementing declaration, the compiler can remove the declaring declaration at compile time. The following conditions apply to partial members: - Declarations must begin with the contextual keyword [partial](../../language-reference/keywords/partial-type.md). - Signatures in both parts of the partial type must match. -The `partial` keyword isn't allowed on constructors, finalizers, overloaded operators, or event declarations. Before C# 13, `partial` wasn't allowed on properties or indexers. +The `partial` keyword isn't allowed on static constructors, finalizers, or overloaded operators. Before C# 14, `partial` wasn't allowed on instance constructors or event declarations. Before C# 13, `partial` wasn't allowed on properties or indexers. A partial method isn't required to have an implementing declaration in the following cases: @@ -23,12 +23,14 @@ A partial method isn't required to have an implementing declaration in the follo - It doesn't have any [`out`](method-parameters.md#out-parameter-modifier) parameters. - It doesn't have any of the following modifiers [`virtual`](../../language-reference/keywords/virtual.md), [`override`](../../language-reference/keywords/override.md), [`sealed`](../../language-reference/keywords/sealed.md), [`new`](../../language-reference/keywords/new-modifier.md), or [`extern`](../../language-reference/keywords/extern.md). -Any member that doesn't conform to all those restrictions (for example, `public virtual partial void` method), must provide an implementation. Partial properties and indexers must have an implementation. - The following example shows a partial method that conforms to the preceding restrictions: :::code language="csharp" source="./snippets/PartialMembers.cs" id="OptionalPartialMethod"::: +Any member that doesn't conform to all those restrictions (for example, `public virtual partial void` method), must provide an implementation. + +Partial properties, indexers, and events can't use auto-implemented syntax for the implementing declaration. The defining declaration uses the same syntax. The implementing declaration must include at least one implemented accessor. That accessor can be a [field-backed property](./field.md). The implementing declaration for a partial event must define the `add` and `remove` handlers. + Partial members can also be useful in combination with source generators. For example a regex could be defined using the following pattern: :::code language="csharp" source="./snippets/PartialMembers.cs" id="SourceGeneratorPartial"::: diff --git a/docs/csharp/language-reference/keywords/partial-type.md b/docs/csharp/language-reference/keywords/partial-type.md index 187d29d2915e5..51617b1b21ff0 100644 --- a/docs/csharp/language-reference/keywords/partial-type.md +++ b/docs/csharp/language-reference/keywords/partial-type.md @@ -1,7 +1,7 @@ --- description: "A partial type is a type declaration that allows you to split the declaration of the type into multiple files." title: "Partial type" -ms.date: 08/15/2024 +ms.date: 03/13/2025 f1_keywords: - "partialtype" - "partialtype_CSharpKeyword" @@ -18,9 +18,9 @@ The other declaration contains the implementation of the partial members: :::code language="csharp" source="./snippets/PartialMembers.cs" id="ImplementingPart"::: -The declarations for a partial type can appear in either the same or multiple files. Typically, the two declarations are in different files. You split a class, struct, or interface type when you're working with large projects, or with automatically generated code such as that provided by the [Windows Forms Designer](/dotnet/desktop/winforms/controls/developing-windows-forms-controls-at-design-time) or [Source generators like RegEx](../../../standard/base-types/regular-expression-source-generators.md). A partial type can contain [partial members](partial-member.md). +The declarations for a partial type can appear in either the same or multiple files. Typically, the two declarations are in different files. You split a class, struct, or interface type when you're working with large projects, with automatically generated code such as that provided by the [Windows Forms Designer](/dotnet/desktop/winforms/controls/developing-windows-forms-controls-at-design-time), or [Source generators like RegEx](../../../standard/base-types/regular-expression-source-generators.md). A partial type can contain [partial members](partial-member.md). -Beginning with C# 13, you can define partial properties and partial indexers. Before C# 13, only methods could be defined as partial members. +Beginning with C# 13, you can define partial properties and partial indexers. Beginning with C# 14, you can define partial instance constructors and partial events. Before C# 13, only methods could be defined as partial members. Documentation comments can be provided on either the declaring declaration or the implementing declaration. When documentation comments are applied to both type declarations, the XML elements from each declaration are included in the output XML. See the article on [partial members](./partial-member.md) for the rules on partial member declarations. diff --git a/docs/csharp/language-reference/keywords/remove.md b/docs/csharp/language-reference/keywords/remove.md index 7d51ed57bfa6f..b432d7f8b142d 100644 --- a/docs/csharp/language-reference/keywords/remove.md +++ b/docs/csharp/language-reference/keywords/remove.md @@ -1,24 +1,21 @@ --- -description: "remove contextual keyword - C# Reference" -title: "remove contextual keyword" -ms.date: 07/20/2015 +description: "The `remove` contextual keyword declares an event accessor that removes a handler from that event. - C# Reference" +title: "The `remove` contextual keyword" +ms.date: 03/13/2025 f1_keywords: - "remove_CSharpKeyword" helpviewer_keywords: - "remove event accessor [C#]" -ms.assetid: c8223426-c17b-4fe2-8406-01564cf1dd2b --- -# remove (C# Reference) +# The `remove` contextual keyword (C# Reference) The `remove` contextual keyword is used to define a custom event accessor that is invoked when client code unsubscribes from your [event](event.md). If you supply a custom `remove` accessor, you must also supply an [add](add.md) accessor. -## Example - The following example shows an event with custom [add](add.md) and `remove` accessors. For the full example, see [How to implement interface events](../../programming-guide/events/how-to-implement-interface-events.md). - [!code-csharp[csrefKeywordsContextual#15](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsContextual/CS/csrefKeywordsContextual.cs#15)] +:::code language="csharp" source="./snippets/events.cs" id="AddHandler"::: -You do not typically need to provide your own custom event accessors. The accessors that are automatically generated by the compiler when you declare an event are sufficient for most scenarios. +You don't typically need to provide your own custom event accessors. The automatically generated accessors when you declare an event are sufficient for most scenarios. Beginning with C# 14, you can declare [`partial`](./partial-member.md) events. The implementing declaration of a partial event must declare the `add` and `remove` handlers. ## See also diff --git a/docs/csharp/language-reference/keywords/snippets/events.cs b/docs/csharp/language-reference/keywords/snippets/events.cs new file mode 100644 index 0000000000000..7ab33ea1147cb --- /dev/null +++ b/docs/csharp/language-reference/keywords/snippets/events.cs @@ -0,0 +1,45 @@ +namespace Events; + +// +public class SampleEventArgs +{ + public SampleEventArgs(string text) { Text = text; } + public string Text { get; } // readonly +} + +public class Publisher +{ + // Declare the delegate (if using non-generic pattern). + public delegate void SampleEventHandler(object sender, SampleEventArgs e); + + // Declare the event. + public event SampleEventHandler SampleEvent; + + // Wrap the event in a protected virtual method + // to enable derived classes to raise the event. + protected virtual void RaiseSampleEvent() + { + // Raise the event in a thread-safe manner using the ?. operator. + SampleEvent?.Invoke(this, new SampleEventArgs("Hello")); + } +} +// + +interface IDrawingObject +{ + event EventHandler OnDraw; +} + +// +class Events : IDrawingObject +{ + event EventHandler PreDrawEvent; + + event EventHandler IDrawingObject.OnDraw + { + add => PreDrawEvent += value; + remove => PreDrawEvent -= value; + } +} +// + diff --git a/docs/csharp/programming-guide/classes-and-structs/constructors.md b/docs/csharp/programming-guide/classes-and-structs/constructors.md index 88c8232459985..770a31d9aac98 100644 --- a/docs/csharp/programming-guide/classes-and-structs/constructors.md +++ b/docs/csharp/programming-guide/classes-and-structs/constructors.md @@ -1,7 +1,7 @@ --- title: "Constructors" description: A constructor in C# is called when a class or struct is created. Use constructors to set defaults, limit instantiation, and write flexible, easy-to-read code. -ms.date: 01/15/2025 +ms.date: 03/11/2025 helpviewer_keywords: - "constructors [C#]" - "classes [C#], constructors" @@ -24,13 +24,15 @@ The preceding actions take place when an instance is created using the [`new` op The [static constructor](static-constructors.md), if any, runs before any of the instance constructor actions take place for any instance of the type. The static constructor runs at most once. +Beginning with C# 14, you can declare instance constructors as [partial members](./partial-classes-and-methods.md). [Partial constructors](#partial-constructors) must have both a declaring and implementing declaration. + ## Constructor syntax A constructor is a method with the same name as its type. Its method signature can include an optional [access modifier](./access-modifiers.md), the method name, and its parameter list; it doesn't include a return type. The following example shows the constructor for a class named `Person`. :::code source="./snippets/constructors/Program.cs" id="InstanceCtor"::: -If a constructor can be implemented as a single statement, you can use an [expression body member](../statements-expressions-operators/expression-bodied-members.md). The following example defines a `Location` class whose constructor has a single string parameter named *name*. The expression body definition assigns the argument to the `locationName` field. +If a constructor can be implemented as a single statement, you can use an [expression body member](../statements-expressions-operators/expression-bodied-members.md). The following example defines a `Location` class whose constructor has a single string parameter, `name`. The expression body definition assigns the argument to the `locationName` field. :::code source="./snippets/constructors/Program.cs" id="ExpressionBodiedCtor"::: @@ -38,6 +40,8 @@ If a type requires a parameter to create an instance, you can use a *primary con :::code source="./snippets/constructors/Program.cs" id="PrimaryCtor"::: +You can declare a primary constructor on a `partial` type. Only one primary constructor declaration is allowed. In other words, only one declaration of the `partial` type can include the parameters for the primary constructor. + ## Static constructors The previous examples show instance constructors, which initialize a new object. A class or struct can also declare a static constructor, which initializes static members of the type. Static constructors are parameterless. If you don't provide a static constructor to initialize static fields, the C# compiler initializes static fields to their default value as listed in the [Default values of C# types](../../language-reference/builtin-types/default-values.md) article. @@ -52,6 +56,10 @@ You can also define a static constructor with an expression body definition, as For more information and examples, see [Static Constructors](./static-constructors.md). +## Partial constructors + +Beginning with C# 14, you can declare *partial constructors* in a partial class or struct. Any partial constructor must have a *defining declaration* and an *implementing declaration*. The signatures of the declaring and implementing partial constructors must match according to the rules of [partial members](./partial-classes-and-methods.md#partial-members). The defining declaration of the partial constructor can't use the `: base()` or `: this()` constructor initializer. You add any constructor initializer must be added on the implementing declaration. + ## See also - [The C# type system](../../fundamentals/types/index.md) 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 453df520a446a..4598d32d1c20d 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 @@ -1,15 +1,16 @@ --- -title: "Partial Classes and Methods" -description: Partial classes and methods in C# split the definition of a class, a struct, an interface, or a method over two or more source files. -ms.date: 10/31/2024 +title: "Partial Classes and Members" +description: Partial classes and members in C# split the definition of a class, a struct, an interface, or a member over two or more source files. +ms.date: 03/11/2025 helpviewer_keywords: - "partial methods [C#]" + - "partial members [C#]" - "partial classes [C#]" - "C# language, partial classes and methods" --- -# Partial Classes and Methods (C# Programming Guide) +# Partial Classes and Members (C# Programming Guide) -It's possible to split the definition of a [class](../../language-reference/keywords/class.md), a [struct](../../language-reference/builtin-types/struct.md), an [interface](../../language-reference/keywords/interface.md), or a method over two or more source files. Each source file contains a section of the type or method definition, and all parts are combined when the application is compiled. +It's possible to split the definition of a [class](../../language-reference/keywords/class.md), a [struct](../../language-reference/builtin-types/struct.md), an [interface](../../language-reference/keywords/interface.md), or a member over two or more source files. Each source file contains a section of the type or member definition, and all parts are combined when the application is compiled. ## Partial Classes @@ -32,7 +33,7 @@ If any part is declared abstract, then the whole type is considered abstract. If All the parts that specify a base class must agree, but parts that omit a base class still inherit the base type. Parts can specify different base interfaces, and the final type implements all the interfaces listed by all the partial declarations. Any class, struct, or interface members declared in a partial definition are available to all the other parts. The final type is the combination of all the parts at compile time. > [!NOTE] -> The `partial` modifier is not available on delegate or enumeration declarations. +> The `partial` modifier isn't available on delegate or enumeration declarations. The following example shows that nested types can be partial, even if the type they're nested within isn't partial itself. @@ -114,9 +115,9 @@ An implementation isn't required for a partial method when the signature obeys t The method and all calls to the method are removed at compile time when there's no implementation. -Any method that doesn't conform to all those restrictions, including properties and indexers, must provide an implementation. That implementation might be supplied by a *source generator*. [Partial properties](../../language-reference/keywords/partial-member.md) can't be implemented using automatically implemented properties. The compiler can't distinguish between an automatically implemented property, and the declaring declaration of a partial property. +Any member that doesn't conform to all those restrictions, including constructors, properties, indexers, and events, must provide an implementation. That implementation might be supplied by a *source generator*. [Partial properties](../../language-reference/keywords/partial-member.md) can't be implemented using automatically implemented properties. The compiler can't distinguish between an automatically implemented property, and the declaring declaration of a partial property. -Beginning with C# 13, the implementing declaration for a partial property can use [field backed properties](../../language-reference/keywords/field.md) to define the implementing declaration. A field backed property provides a concise syntax where the `field` keyword accesses the compiler synthesized backing field for the property. For example, you could write the following: +Beginning with C# 13, the implementing declaration for a partial property can use [field backed properties](../../language-reference/keywords/field.md) to define the implementing declaration. A field backed property provides a concise syntax where the `field` keyword accesses the compiler synthesized backing field for the property. For example, you could write the following code: :::code language="csharp" source="snippets/partial-classes-and-methods/Program.cs" id="FieldProperty"::: @@ -124,7 +125,7 @@ You can use `field` in either the `get` or `set` accessor, or both. [!INCLUDE[field-preview](../../includes/field-preview.md)] -Partial methods enable the implementer of one part of a class to declare a member. The implementer of another part of the class can define that member. There are two scenarios where this separation is useful: templates that generate boilerplate code, and source generators. +Partial members enable the implementer of one part of a class to declare a member. The implementer of another part of the class can define that member. There are two scenarios where this separation is useful: templates that generate boilerplate code, and source generators. - **Template code**: The template reserves a method name and signature so that generated code can call the method. These methods follow the restrictions that enable a developer to decide whether to implement the method. If the method isn't implemented, then the compiler removes the method signature and all calls to the method. The calls to the method, including any results that would occur from evaluation of arguments in the calls, have no effect at run time. Therefore, any code in the partial class can freely use a partial method, even if the implementation isn't supplied. No compile-time or run-time errors result if the method is called but not implemented. - **Source generators**: Source generators provide an implementation for members. The human developer can add the member declaration (often with attributes read by the source generator). The developer can write code that calls these members. The source generator runs during compilation and provides the implementation. In this scenario, the restrictions for partial members that might not be implemented often aren't followed. @@ -143,12 +144,12 @@ partial void OnNameChanged() - Partial member declarations must begin with the contextual keyword [partial](../../language-reference/keywords/partial-type.md). - Partial member signatures in both parts of the partial type must match. - Partial member can have [static](../../language-reference/keywords/static.md) and [unsafe](../../language-reference/keywords/unsafe.md) modifiers. -- Partial member can be generic. Constraints must be the same on the defining and implementing method declaration. Parameter and type parameter names don't have to be the same in the implementing declaration as in the defining one. +- Partial member can be generic. Constraints must be the same on the defining and implementing member declaration. Parameter and type parameter names don't have to be the same in the implementing declaration as in the defining one. - You can make a [delegate](../../language-reference/builtin-types/reference-types.md) to a partial method defined and implemented, but not to a partial method that doesn't have an implementation. ## 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 methods are defined in the [feature specification](~/_csharplang/proposals/csharp-9.0/extending-partial-methods.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/partial-events-and-constructors.md). ## See also diff --git a/docs/csharp/programming-guide/events/index.md b/docs/csharp/programming-guide/events/index.md index 6f18cccb65f5c..448574f9efdf7 100644 --- a/docs/csharp/programming-guide/events/index.md +++ b/docs/csharp/programming-guide/events/index.md @@ -1,53 +1,43 @@ --- title: "Events" description: Learn about events. Events enable a class or object to notify other classes or objects when something of interest occurs. -ms.date: 07/20/2015 +ms.date: 03/11/2025 helpviewer_keywords: - "classes [C#], events" - "C# language, events" - "events [C#]" -ms.assetid: a8e51b22-d294-44fb-9539-0072f06c4cb3 --- # Events (C# Programming Guide) -Events enable a [class](../../language-reference/keywords/class.md) or object to notify other classes or objects when something of interest occurs. The class that sends (or *raises*) the event is called the *publisher* and the classes that receive (or *handle*) the event are called *subscribers*. - +Events enable a [class](../../language-reference/keywords/class.md) or object to notify other classes or objects when something of interest occurs. The class that sends (or *raises*) the event is called the *publisher* and the classes that receive (or *handle*) the event are called *subscribers*. + In a typical C# Windows Forms or Web application, you subscribe to events raised by controls such as buttons and list boxes. You can use the Visual C# integrated development environment (IDE) to browse the events that a control publishes and select the ones that you want to handle. The IDE provides an easy way to automatically add an empty event handler method and the code to subscribe to the event. For more information, see [How to subscribe to and unsubscribe from events](./how-to-subscribe-to-and-unsubscribe-from-events.md). - -## Events Overview - - Events have the following properties: - -- The publisher determines when an event is raised; the subscribers determine what action is taken in response to the event. - -- An event can have multiple subscribers. A subscriber can handle multiple events from multiple publishers. - -- Events that have no subscribers are never raised. - -- Events are typically used to signal user actions such as button clicks or menu selections in graphical user interfaces. - -- When an event has multiple subscribers, the event handlers are invoked synchronously when an event is raised. To invoke events asynchronously, see [Calling Synchronous Methods Asynchronously](../../../standard/asynchronous-programming-patterns/calling-synchronous-methods-asynchronously.md). - -- In the .NET class library, events are based on the delegate and the base class. - -## Related Sections - - For more information, see: - -- [How to subscribe to and unsubscribe from events](./how-to-subscribe-to-and-unsubscribe-from-events.md) -- [How to publish events that conform to .NET Guidelines](/dotnet/standard/events) +## Events Overview -- [How to raise base class events in derived classes](./how-to-raise-base-class-events-in-derived-classes.md) +Events have the following properties: -- [How to implement interface events](./how-to-implement-interface-events.md) +- The publisher determines when an event is raised; the subscribers determine what action is taken in response to the event. +- An event can have multiple subscribers. A subscriber can handle multiple events from multiple publishers. +- Events that have no subscribers are never raised. +- Events are typically used to signal user actions such as button clicks or menu selections in graphical user interfaces. +- When an event has multiple subscribers, the event handlers are invoked synchronously when an event is raised. To invoke events asynchronously, see [Calling Synchronous Methods Asynchronously](../../../standard/asynchronous-programming-patterns/calling-synchronous-methods-asynchronously.md). +- In the .NET class library, events are based on the delegate and the base class. + +## Related Sections + For more information, see: + +- [How to subscribe to and unsubscribe from events](./how-to-subscribe-to-and-unsubscribe-from-events.md) +- [How to publish events that conform to .NET Guidelines](/dotnet/standard/events) +- [How to raise base class events in derived classes](./how-to-raise-base-class-events-in-derived-classes.md) +- [How to implement interface events](./how-to-implement-interface-events.md) - [How to implement custom event accessors](./how-to-implement-custom-event-accessors.md) -## C# Language Specification +## C# Language Specification For more information, see [Events](~/_csharpstandard/standard/classes.md#158-events) in the [C# Language Specification](~/_csharpstandard/standard/README.md). The language specification is the definitive source for C# syntax and usage. - + ## See also - diff --git a/docs/csharp/specification/toc.yml b/docs/csharp/specification/toc.yml index 56dbe3ff9267f..bcc71fe59011e 100644 --- a/docs/csharp/specification/toc.yml +++ b/docs/csharp/specification/toc.yml @@ -201,6 +201,8 @@ items: href: ../../../_csharplang/proposals/csharp-9.0/extending-partial-methods.md - 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 - name: Field backed properties (preview) href: ../../../_csharplang/proposals/field-keyword.md - name: Covariant return types diff --git a/docs/csharp/whats-new/csharp-14.md b/docs/csharp/whats-new/csharp-14.md index 21c15e42a8726..ad68a7a62985f 100644 --- a/docs/csharp/whats-new/csharp-14.md +++ b/docs/csharp/whats-new/csharp-14.md @@ -12,6 +12,7 @@ C# 14 includes the following new features. You can try these features using the - [More implicit conversions for `Span` and `ReadOnlySpan`](#implicit-span-conversions) - [Modifiers on simple lambda parameters](#simple-lambda-parameters-with-modifiers) - [`field` backed properties](#the-field-keyword) +- [`partial` events and constructors](#more-partial-members) C# 14 is supported on **.NET 10**. For more information, see [C# language versioning](../language-reference/configure-language-version.md). @@ -50,11 +51,11 @@ public string Message You can declare a body for one or both accessors for a field backed property. -There's a potential breaking change or confusion reading code in types that also include a symbol named `field`. You can use `@field` or `this.field` to disambiguate between the `field` keyword and the identifier, or you can rename the current `field` symbol to provide more distinction. +There's a potential breaking change or confusion reading code in types that also include a symbol named `field`. You can use `@field` or `this.field` to disambiguate between the `field` keyword and the identifier, or you can rename the current `field` symbol to provide better distinction. If you try this feature and have feedback, comment on the [feature issue](https://github.com/dotnet/csharplang/issues/140) in the `csharplang` repository. -The [`field`](../language-reference/keywords/field.md) contextual keyword is in C# 13 as a preview feature. You can try it if you're using .NET 9 and C# 13 to provide [feedback](https://github.com/dotnet/csharplang/issues/140). +The [`field`](../language-reference/keywords/field.md) contextual keyword is in C# 13 as a preview feature. ## Implicit span conversions @@ -64,13 +65,13 @@ C# 14 introduces first-class support for )` evaluates to `List`. In earlier versions of C#, only closed generic types, such as `List`, could be used to return the `List` name. ## Simple lambda parameters with modifiers -Beginning with C# 14, you can add parameter modifiers, such as `scoped`, `ref`, `in`, `out`, or `ref readonly` to lambda expression parameters without specifying the parameter type: +You can add parameter modifiers, such as `scoped`, `ref`, `in`, `out`, or `ref readonly` to lambda expression parameters without specifying the parameter type: ```csharp delegate bool TryParse(string text, out T result); @@ -88,6 +89,16 @@ The `params` modifier still requires an explicitly typed parameter list. You can read more about these changes in the article on [lambda expressions](../language-reference/operators/lambda-expressions.md#input-parameters-of-a-lambda-expression) in the C# language reference. +## More partial members + +You can now declare [instance constructors](../programming-guide/classes-and-structs/constructors.md#partial-constructors) and [events](../event-pattern.md) as [partial members](../language-reference/keywords/partial-member.md). + +Partial constructors and partial events must include exactly one *defining declaration* and one *implementing declaration*. + +Only the implementing declaration of a partial constructor can include a constructor initializer: `this()` or `base()`. Only one partial type declaration can include the primary constructor syntax. + +The implementing declaration of a partial event must include `get` and `remove` accessors. The defining declaration declares a field-like event. + ## See also - [What's new in .NET 10](../../core/whats-new/dotnet-10/overview.md) diff --git a/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsContextual/CS/csrefKeywordsContextual.cs b/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsContextual/CS/csrefKeywordsContextual.cs index 75314e646778f..9e5a0f85bf488 100644 --- a/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsContextual/CS/csrefKeywordsContextual.cs +++ b/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsContextual/CS/csrefKeywordsContextual.cs @@ -78,21 +78,4 @@ join prod in products on category.ID equals prod.CategoryID } } - interface IDrawingObject - { - event EventHandler OnDraw; - } - - // - class Events : IDrawingObject - { - event EventHandler PreDrawEvent; - - event EventHandler IDrawingObject.OnDraw - { - add => PreDrawEvent += value; - remove => PreDrawEvent -= value; - } - } - // } diff --git a/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsModifiers/CS/csrefKeywordsModifiers.cs b/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsModifiers/CS/csrefKeywordsModifiers.cs index 96345027ae440..3204553d3476b 100644 --- a/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsModifiers/CS/csrefKeywordsModifiers.cs +++ b/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsModifiers/CS/csrefKeywordsModifiers.cs @@ -214,31 +214,6 @@ static void Main() // Output: My local constant = 707 // - // - public class SampleEventArgs - { - public SampleEventArgs(string text) { Text = text; } - public string Text { get; } // readonly - } - - public class Publisher - { - // Declare the delegate (if using non-generic pattern). - public delegate void SampleEventHandler(object sender, SampleEventArgs e); - - // Declare the event. - public event SampleEventHandler SampleEvent; - - // Wrap the event in a protected virtual method - // to enable derived classes to raise the event. - protected virtual void RaiseSampleEvent() - { - // Raise the event in a thread-safe manner using the ?. operator. - SampleEvent?.Invoke(this, new SampleEventArgs("Hello")); - } - } - // - // //using System.Runtime.InteropServices; class ExternTest