Skip to content

Commit

Permalink
Pass base pipeline, add sample
Browse files Browse the repository at this point in the history
  • Loading branch information
heaths committed Mar 28, 2023
1 parent 0680e61 commit 71e700b
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ description: Samples for the Azure.Security.KeyVault.Secrets client library.
- [Creating, getting, updating, and deleting secrets](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/keyvault/Azure.Security.KeyVault.Secrets/samples/Sample1_HelloWorld.md)
- [Back up and restore a secret](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/keyvault/Azure.Security.KeyVault.Secrets/samples/Sample2_BackupAndRestore.md)
- [Listing secrets, secret versions, and deleted secrets](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/keyvault/Azure.Security.KeyVault.Secrets/samples/Sample3_GetSecrets.md)
- [Get a secret without throwing if it is not defined](https://github.com/heaths/azure-sdk-for-net/blob/main/sdk/keyvault/Azure.Security.KeyVault.Secrets/samples/Sample4_GetSecretIfExists.md)
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Get a secret without throwing if it is not defined

This sample demonstrates how to get a secret without throwing an exception if it is not defined.
This may be useful in some application configuration managers that attempt to fetch key/value pairs from a collection of providers and when exceptions may break startup or are otherwise costly.
To better configure ASP.NET applications or other applications that use common [.NET Configuration], see our documentation on [Azure.Extensions.AspNetCore.Configuration.Secrets].
To get started, you'll need a URI to an Azure Key Vault. See the [README](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/keyvault/Azure.Security.KeyVault.Secrets/README.md) for links and instructions.

## Creating a SecretClient

To create a new `SecretClient` to create get a secret, you need the endpoint to an Azure Key Vault and credentials.
You can use the [DefaultAzureCredential] to try a number of common authentication methods optimized for both running as a service and development.

In the sample below, you can set `keyVaultUrl` based on an environment variable, configuration setting, or any way that works for your application.

```C# Snippet:SecretsSample4SecretClient
var client = new SecretClient(new Uri(keyVaultUrl), new DefaultAzureCredential());
```

## Get a secret

To prevent throwing a `RequestFailedException` when a secret does not exist, or to alter other behaviors of a specific API call, you can create a `RequestContext` and pass that to the API call:

```C# Snippet:SecretsSample4GetSecretIfExists
// Do not treat HTTP 404 responses as errors.
RequestContext context = new RequestContext();
context.AddClassifier(404, false);

// Try getting the latest application connection string using the context above.
NullableResponse<KeyVaultSecret> response = client.GetSecret("appConnectionString", null, context);
if (response.HasValue)
{
KeyVaultSecret secret = response.Value;
Debug.WriteLine($"Secret is returned with name {secret.Name} and value {secret.Value}");
}
```

You can also do this asynchronously:

```C# Snippet:SecretsSample4GetSecretIfExistsAsync
// Do not treat HTTP 404 responses as errors.
RequestContext context = new RequestContext();
context.AddClassifier(404, false);

// Try getting the latest application connection string using the context above.
NullableResponse<KeyVaultSecret> response = await client.GetSecretAsync("appConnectionString", null, context);
if (response.HasValue)
{
KeyVaultSecret secret = response.Value;
Debug.WriteLine($"Secret is returned with name {secret.Name} and value {secret.Value}");
}
```

[.NET Configuration]: https://learn.microsoft.com/dotnet/core/extensions/configuration
[Azure.Extensions.AspNetCore.Configuration.Secrets]: https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/extensions/Azure.Extensions.AspNetCore.Configuration.Secrets/README.md
[DefaultAzureCredential]: https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/identity/Azure.Identity/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class SampleFixture: SamplesBase<KeyVaultTestEnvironment>
public partial class HelloWorld : SampleFixture { }
public partial class BackupAndRestore : SampleFixture { }
public partial class GetSecrets : SampleFixture { }
public partial class GetSecretIfExists : SampleFixture { }
public partial class Snippets : SampleFixture { }
#pragma warning restore SA1402 // File may only contain a single type
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Diagnostics;
using System.Threading.Tasks;
using NUnit.Framework;

namespace Azure.Security.KeyVault.Secrets.Samples
{
public partial class GetSecretIfExists
{
[Test]
public void GetSecretIfExistsSync()
{
// Environment variable with the Key Vault endpoint.
string keyVaultUrl = TestEnvironment.KeyVaultUrl;

#region Snippet:SecretsSample4SecretClient
var client = new SecretClient(new Uri(keyVaultUrl), new DefaultAzureCredential());
#endregion

#region Snippet:SecretsSample4GetSecretIfExists
// Do not treat HTTP 404 responses as errors.
RequestContext context = new RequestContext();
context.AddClassifier(404, false);

// Try getting the latest application connection string using the context above.
NullableResponse<KeyVaultSecret> response = client.GetSecret("appConnectionString", null, context);
if (response.HasValue)
{
KeyVaultSecret secret = response.Value;
Debug.WriteLine($"Secret is returned with name {secret.Name} and value {secret.Value}");
}
#endregion
}

[Test]
public async Task GetSecretIfExistsAsync()
{
// Environment variable with the Key Vault endpoint.
string keyVaultUrl = TestEnvironment.KeyVaultUrl;

var client = new SecretClient(new Uri(keyVaultUrl), new DefaultAzureCredential());

#region Snippet:SecretsSample4GetSecretIfExistsAsync
// Do not treat HTTP 404 responses as errors.
RequestContext context = new RequestContext();
context.AddClassifier(404, false);

// Try getting the latest application connection string using the context above.
NullableResponse<KeyVaultSecret> response = await client.GetSecretAsync("appConnectionString", null, context);
if (response.HasValue)
{
KeyVaultSecret secret = response.Value;
Debug.WriteLine($"Secret is returned with name {secret.Name} and value {secret.Value}");
}
#endregion
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public HttpMessage CreateMessage(RequestMethod method, Uri uri, bool appendApiVe
public HttpMessage CreateMessage(RequestMethod method, RequestContext context, params string[] path)
{
// See comment in CreateMessage overload above for future design consideration.
HttpMessage message = _pipeline.CreateMessage(context);
HttpMessage message = _pipeline.CreateMessage(context, DefaultResponseClassifier);
Request request = message.Request;

request.Headers.Add(HttpHeader.Common.JsonContentType);
Expand Down Expand Up @@ -294,7 +294,6 @@ public Response GetResponse(RequestMethod method, CancellationToken cancellation

private async ValueTask SendRequestAsync(HttpMessage message, CancellationToken cancellationToken)
{
message.ResponseClassifier ??= ResponseClassifier200201202204;
await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false);

if (message.ResponseClassifier.IsErrorResponse(message))
Expand All @@ -305,7 +304,6 @@ private async ValueTask SendRequestAsync(HttpMessage message, CancellationToken

private void SendRequest(HttpMessage message, CancellationToken cancellationToken)
{
message.ResponseClassifier ??= ResponseClassifier200201202204;
_pipeline.Send(message, cancellationToken);

if (message.ResponseClassifier.IsErrorResponse(message))
Expand All @@ -314,8 +312,8 @@ private void SendRequest(HttpMessage message, CancellationToken cancellationToke
}
}

private static ResponseClassifier s_responseClassifier200201202204;
private static ResponseClassifier ResponseClassifier200201202204 => s_responseClassifier200201202204 ??= new StatusCodeClassifier(stackalloc ushort[]
private static ResponseClassifier s_defaultResponseClassifier;
private static ResponseClassifier DefaultResponseClassifier => s_defaultResponseClassifier ??= new StatusCodeClassifier(stackalloc ushort[]
{
200,
201,
Expand Down

0 comments on commit 71e700b

Please sign in to comment.