Skip to content

Commit 45b9c21

Browse files
committed
sample code
1 parent 6987420 commit 45b9c21

26 files changed

+801
-166
lines changed

docs/azure/sdk/aspnetcore-guidance.md

Lines changed: 22 additions & 166 deletions
Original file line numberDiff line numberDiff line change
@@ -37,70 +37,17 @@ Complete the following steps to register the services you need:
3737
3838
3. In the `Program.cs` file, invoke the `AddAzureClients` extension method from the `Microsoft.Extensions.Azure` library to register a client for each service. Some services use additional subclients, which you can also register for dependency injection.
3939
40-
```csharp
41-
builder.Services.AddAzureClients(clientBuilder =>
42-
{
43-
// Register clients for each Azure service
44-
clientBuilder.AddSecretClient(new Uri("<key_vault_url>"));
45-
clientBuilder.AddBlobServiceClient(new Uri("<storage_url>"));
46-
clientBuilder.AddServiceBusClientWithNamespace(
47-
"<your_namespace>.servicebus.windows.net");
48-
49-
// Register a shared credential for Microsoft Entra ID authentication
50-
clientBuilder.UseCredential(new DefaultAzureCredential());
51-
52-
// Register a subclient for each Azure Service Bus Queue
53-
foreach (string queue in queueNames)
54-
{
55-
clientBuilder.AddClient<ServiceBusSender, ServiceBusClientOptions>(
56-
(_, _, provider) => provider.GetService<ServiceBusClient>()
57-
.CreateSender(queue)).WithName(queue);
58-
}
59-
});
60-
```
40+
:::code source="snippets/aspnetcore-guidance/BlazorSample/Program.cs" range="11-30":::
6141
6242
4. Inject the registered services into your ASP.NET Core app components, services, or API endpoint methods:
6343
6444
## [Minimal API](#tab/api)
6545
66-
```csharp
67-
app.MapPost("/reports", async (BlobServiceClient blobServiceClient) =>
68-
{
69-
// Use the blob client
70-
BlobContainerClient containerClient
71-
= await blobServiceClient.CreateBlobContainerAsync("reports");
72-
});
73-
```
46+
:::code source="snippets/aspnetcore-guidance/MinApiSample/Program.cs" range="44-59":::
7447
7548
## [Blazor](#tab/blazor)
7649
77-
```csharp
78-
@page "/reports"
79-
@inject BlobServiceClient blobservice
80-
81-
<h1>Reports</h1>
82-
83-
<ul>
84-
@foreach(var report in reports)
85-
{
86-
<li>@report.Name</li>
87-
}
88-
</ul>
89-
90-
@code {
91-
List<BlobItem> reports = new();
92-
93-
protected override async Task OnInitializedAsync()
94-
{
95-
BlobContainerClient containerClient = blobservice.GetBlobContainerClient("reports");
96-
97-
await foreach (BlobItem blobItem in containerClient.GetBlobsAsync())
98-
{
99-
reports.Add(blobItem);
100-
}
101-
}
102-
}
103-
```
50+
:::code source="snippets/aspnetcore-guidance/BlazorSample/Program.cs" range="1-28" highlight="5,21":::
10451
10552
---
10653
@@ -112,27 +59,7 @@ Some Azure services also allow you to authorize requests using secrets keys. How
11259
11360
Consider the following service client registrations:
11461
115-
```csharp
116-
builder.Services.AddAzureClients(clientBuilder =>
117-
{
118-
// Register clients for each Azure service
119-
clientBuilder.AddSecretClient(new Uri("<key_vault_url>"));
120-
clientBuilder.AddBlobServiceClient(new Uri("<storage_url>"));
121-
clientBuilder.AddServiceBusClientWithNamespace(
122-
"<your_namespace>.servicebus.windows.net");
123-
124-
// Register a shared credential for Microsoft Entra ID authentication
125-
clientBuilder.UseCredential(new DefaultAzureCredential());
126-
127-
// Register a subclient for each Azure Service Bus Queue
128-
foreach (string queue in queueNames)
129-
{
130-
clientBuilder.AddClient<ServiceBusSender, ServiceBusClientOptions>(
131-
(_, _, provider) => provider.GetService<ServiceBusClient>()
132-
.CreateSender(queue)).WithName(queue);
133-
}
134-
});
135-
```
62+
:::code source="snippets/aspnetcore-guidance/BlazorSample/Program.cs" range="29":::
13663
13764
In the preceding code, the `clientBuilder.UseCredential()` method accepts an instance of `DefaultAzureCredential` that will be reused across your registered services. `DefaultAzureCredential` discovers available credentials in the current environment and use them to connect to Azure services. The full order and locations in which `DefaultAzureCredential` looks for credentials can be found in the [`Azure Identity library overview`](/dotnet/api/overview/azure/Identity-readme#defaultazurecredential).
13865
@@ -150,102 +77,41 @@ For example, when you run the app locally, `DefaultAzureCredential` discovers an
15077
- Workload identity
15178
- Managed identity
15279
153-
## Set up service configurations
80+
## Set up configurations
15481
15582
Azure service clients support configurations to change their default behaviors. There are two ways to configure service clients:
15683
15784
- You can [store configurations in environment-dependent JSON files](/dotnet/core/extensions/configuration-providers#json-configuration-provider). Configuration files are generally the recommended approach because they simplify app deployments between environments and help eliminate hard coded values.
15885
- You can also configurations directly in your code when you register the service client. For example, in the [Register clients and subclients](#register-service-clients-and-subclients) section, you explicitly passed the Uri-typed variables to the client constructors.
15986
160-
The following example uses an `appsettings.Development.json` file to store development environment settings and an `appsettings.Production.json` file to contain production environment settings. You can add any properties from the [`ClientOptions`](/dotnet/api/azure.core.clientoptions) class into the JSON file.
161-
162-
1. Update the `appsettings.<environment>.json` file in your app to match the following structure:
163-
164-
```json
165-
{
166-
"KeyVault": {
167-
"VaultUri": "https://<your-key-vault-name>.vault.azure.net"
168-
},
169-
"Storage": {
170-
"ServiceUri": "https://<your-storage-account-name>.storage.windows.net"
171-
},
172-
"ServiceBus": {
173-
"Namespace": "<your_service-bus_namespace>.servicebus.windows.net"
174-
}
175-
}
176-
```
87+
The following steps use an `appsettings.Development.json` file to store development environment settings and an `appsettings.Production.json` file to contain production environment settings. You can add any properties from the [`ClientOptions`](/dotnet/api/azure.core.clientoptions) class into the JSON file.
88+
89+
### Configure registered services
90+
91+
1. Update the `appsettings.<environment>.json` file in your app with the highlighted service configurations:
92+
93+
:::code source="snippets/aspnetcore-guidance/BlazorSample/appsettings.Development.json" range="19-27":::
17794
17895
In the preceding JSON sample:
17996
18097
- The top-level key names, `KeyVault`, `ServiceBus`, and `Storage`, are arbitrary names used to reference the config sections from your code. All other key names hold significance, and JSON serialization is performed in a case-insensitive manner.
18198
- The `KeyVault:VaultUri`, `ServiceBus:Namespace`, and `Storage:ServiceUri` key values map to the `Uri`- and `string`-typed arguments of the <xref:Azure.Security.KeyVault.Secrets.SecretClient.%23ctor(System.Uri,Azure.Core.TokenCredential,Azure.Security.KeyVault.Secrets.SecretClientOptions)?displayProperty=fullName>, <xref:Azure.Messaging.ServiceBus.ServiceBusClient.%23ctor(System.String)?displayProperty=fullName>, and <xref:Azure.Storage.Blobs.BlobServiceClient.%23ctor(System.Uri,Azure.Core.TokenCredential,Azure.Storage.Blobs.BlobClientOptions)?displayProperty=fullName> constructor overloads, respectively. The `TokenCredential` variants of the constructors are used because a default `TokenCredential` is set via the <xref:Microsoft.Extensions.Azure.AzureClientFactoryBuilder.UseCredential(Azure.Core.TokenCredential)?displayProperty=fullName> method call.
18299
183-
1. Retrieve the settings in the JSON configuration file using `IConfiguration` and pass them into your service registrations:
184-
185-
```csharp
186-
builder.Services.AddAzureClients(clientBuilder =>
187-
{
188-
clientBuilder.AddSecretClient(
189-
builder.Configuration.GetSection("KeyVault"));
190-
191-
clientBuilder.AddBlobServiceClient(
192-
builder.Configuration.GetSection("Storage"));
193-
194-
clientBuilder.AddServiceBusClientWithNamespace(
195-
builder.Configuration["ServiceBus:Namespace"]);
196-
197-
clientBuilder.UseCredential(new DefaultAzureCredential());
198-
});
199-
```
100+
1. Update the the `Program.cs` file to retrieve the JSON file configurations using `IConfiguration` and pass them into your service registrations:
101+
102+
:::code source="snippets/aspnetcore-guidance/BlazorSample/Program.cs" range="13-31":::
200103
201-
### Configure retries and Azure defaults
104+
### Configure Azure defaults and retries
202105
203106
At some point, you may want to change default Azure client configurations globally or for a specific service client. For example, you may want different retry settings or to use a different service API version. You can set the retry settings globally or on a per-service basis.
204107
205108
1. Update your configuration file to set default Azure settings, such as a new default retry policy and a specific retry policy for Azure Key Vault:
206109
207-
```json
208-
{
209-
"AzureDefaults": {
210-
"Diagnostics": {
211-
"IsTelemetryDisabled": false,
212-
"IsLoggingContentEnabled": true
213-
},
214-
"Retry": {
215-
"MaxRetries": 3,
216-
"Mode": "Exponential"
217-
}
218-
},
219-
"KeyVault": {
220-
"VaultUri": "https://mykeyvault.vault.azure.net",
221-
"Retry": {
222-
"maxRetries": 10
223-
}
224-
}
225-
}
226-
```
227-
228-
2. Add a call to the `ConfigureDefaults` extension method in your `AddAzureClients` setup:
229-
230-
```csharp
231-
builder.Services.AddAzureClients(clientBuilder =>
232-
{
233-
clientBuilder.AddSecretClient(
234-
builder.Configuration.GetSection("KeyVault"));
235-
236-
clientBuilder.AddBlobServiceClient(
237-
builder.Configuration.GetSection("Storage"));
238-
239-
clientBuilder.AddServiceBusClientWithNamespace(
240-
builder.Configuration["ServiceBus:Namespace"]);
241-
242-
clientBuilder.UseCredential(new DefaultAzureCredential());
243-
244-
// Set up any default settings
245-
clientBuilder.ConfigureDefaults(
246-
builder.Configuration.GetSection("AzureDefaults"));
247-
});
248-
```
110+
:::code source="snippets/aspnetcore-guidance/BlazorSample/appsettings.Development.json" range="9-23":::
111+
112+
2. In the `Program.cs` file, the `ConfigureDefaults` extension method `AddAzureClients` retrieves the default settings and applies them to your services:
113+
114+
:::code source="snippets/aspnetcore-guidance/BlazorSample/Program.cs" range="13-31":::
249115
250116
## Configure logging
251117
@@ -264,14 +130,4 @@ The following table depicts how the Azure SDK for .NET `EventLevel` maps to the
264130
265131
You can change default log levels and other settings using the same JSON configurations outlined in the [configure authentication](#configure-authentication) section. For example, toggle a the `ServiceBusClient` log level to `Debug` by setting the `Logging:LogLevel:Azure.Messaging.ServiceBus` key as follows:
266132
267-
```json
268-
{
269-
"Logging": {
270-
"LogLevel": {
271-
"Default": "Information",
272-
"Microsoft.AspNetCore": "Warning",
273-
"Azure.Messaging.ServiceBus": "Debug"
274-
}
275-
}
276-
}
277-
```
133+
:::code source="snippets/aspnetcore-guidance/BlazorSample/appsettings.Development.json" range="2-8":::
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net8.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="Azure.Messaging.ServiceBus" Version="7.18.2" />
11+
<PackageReference Include="Azure.Security.KeyVault.Secrets" Version="4.7.0" />
12+
<PackageReference Include="Azure.Storage.Blobs" Version="12.22.2" />
13+
<PackageReference Include="Microsoft.Extensions.Azure" Version="1.7.6" />
14+
</ItemGroup>
15+
16+
</Project>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="utf-8" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<base href="/" />
8+
<link rel="stylesheet" href="bootstrap/bootstrap.min.css" />
9+
<link rel="stylesheet" href="app.css" />
10+
<link rel="stylesheet" href="AspNetCoreAzureSDK.styles.css" />
11+
<link rel="icon" type="image/png" href="favicon.png" />
12+
<HeadOutlet />
13+
</head>
14+
15+
<body>
16+
<Routes />
17+
<script src="_framework/blazor.web.js"></script>
18+
</body>
19+
20+
</html>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
@inherits LayoutComponentBase
2+
3+
<div class="page">
4+
<div class="sidebar">
5+
<NavMenu />
6+
</div>
7+
8+
<main>
9+
<div class="top-row px-4">
10+
<a href="https://learn.microsoft.com/aspnet/core/" target="_blank">About</a>
11+
</div>
12+
13+
<article class="content px-4">
14+
@Body
15+
</article>
16+
</main>
17+
</div>
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
.page {
2+
position: relative;
3+
display: flex;
4+
flex-direction: column;
5+
}
6+
7+
main {
8+
flex: 1;
9+
}
10+
11+
.sidebar {
12+
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
13+
}
14+
15+
.top-row {
16+
background-color: #f7f7f7;
17+
border-bottom: 1px solid #d6d5d5;
18+
justify-content: flex-end;
19+
height: 3.5rem;
20+
display: flex;
21+
align-items: center;
22+
}
23+
24+
.top-row ::deep a, .top-row ::deep .btn-link {
25+
white-space: nowrap;
26+
margin-left: 1.5rem;
27+
text-decoration: none;
28+
}
29+
30+
.top-row ::deep a:hover, .top-row ::deep .btn-link:hover {
31+
text-decoration: underline;
32+
}
33+
34+
.top-row ::deep a:first-child {
35+
overflow: hidden;
36+
text-overflow: ellipsis;
37+
}
38+
39+
@media (max-width: 640.98px) {
40+
.top-row {
41+
justify-content: space-between;
42+
}
43+
44+
.top-row ::deep a, .top-row ::deep .btn-link {
45+
margin-left: 0;
46+
}
47+
}
48+
49+
@media (min-width: 641px) {
50+
.page {
51+
flex-direction: row;
52+
}
53+
54+
.sidebar {
55+
width: 250px;
56+
height: 100vh;
57+
position: sticky;
58+
top: 0;
59+
}
60+
61+
.top-row {
62+
position: sticky;
63+
top: 0;
64+
z-index: 1;
65+
}
66+
67+
.top-row.auth ::deep a:first-child {
68+
flex: 1;
69+
text-align: right;
70+
width: 0;
71+
}
72+
73+
.top-row, article {
74+
padding-left: 2rem !important;
75+
padding-right: 1.5rem !important;
76+
}
77+
}
78+
79+
#blazor-error-ui {
80+
background: lightyellow;
81+
bottom: 0;
82+
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
83+
display: none;
84+
left: 0;
85+
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
86+
position: fixed;
87+
width: 100%;
88+
z-index: 1000;
89+
}
90+
91+
#blazor-error-ui .dismiss {
92+
cursor: pointer;
93+
position: absolute;
94+
right: 0.75rem;
95+
top: 0.5rem;
96+
}

0 commit comments

Comments
 (0)