Last week I wrote about building a typed, cached AWS Secrets Manager library for .NET Framework 4.8 — the design decisions, the trade-offs, and proving it in a real ASP.NET MVC 5 application. That post covered the journey. This one is shorter: DGates.AwsSecretsManager 1.0.0 is now available on NuGet.
If you haven't read the first post, the one-paragraph version: modern .NET gets typed, cached AWS Secrets Manager access essentially for free. .NET Framework 4.8 applications get the raw SDK and nothing else. This library closes that ergonomics gap — typed retrieval via GetSecretAsync<T>, TTL-based (time-to-live) caching, Polly-backed retry for transient failures, and a DI-agnostic factory that works just as well in a Global.asax-era app as in one with a container.
The source, examples, and NuGet package are all available if you'd like to follow along.
Two things changed on the way from beta to stable, and both are worth a few words.
Structured Logging
The beta was silent. You could see what the library did by observing its results, but not why — whether a value came from cache or a live call, when a retry fired, when the local fallback engaged.
1.0.0 adds logging through Microsoft.Extensions.Logging.Abstractions — the abstractions package only, deliberately. A library targeting .NET Framework 4.8 has to be careful about what it drags into a consumer's dependency tree, and a full logging framework is exactly the kind of baggage a legacy application doesn't want imposed on it. The abstractions package is a small dependency that dictates nothing about which logging framework — if any — the consuming application uses.
The wiring is simple: SecretsManagerServiceFactory.Create(...) takes an optional ILogger, and defaults to a no-op logger when you don't pass one. Consumers with an existing logging pipeline — NLog, Serilog, log4net via an adapter — can plug in; consumers without one pay nothing and change nothing.
Fail Fast on Missing Credentials
The beta had a sharp edge: if no AWS credentials were available anywhere, you didn't find out at startup. You found out several calls deep, on the first GetSecretAsync<T>, as a generic AWS authentication error with no obvious connection to configuration.
1.0.0 validates the credential chain at SecretsManagerServiceFactory.Create(...) time. The important detail is how: rather than checking only the library's own settings surface, it resolves credentials through DefaultAWSCredentialsIdentityResolver — the same mechanism the v4 AWS SDK uses internally — to determine whether any source in the credential chain resolves successfully: explicit settings, environment variables, appSettings, an IAM role. If nothing does, you get a clear, descriptive InvalidOperationException at the one place you'd actually look for a configuration problem. If anything does — including credential sources this library knows nothing about — validation passes, because the SDK's chain is the source of truth, not a reimplementation of it.
What Stable Means
From 1.0.0 forward, the library follows semantic versioning. The public API surface — GetSecretAsync<T>, GetSecretStringAsync, RefreshSecretAsync<T>, InvalidateCache, the settings model, and the factory — is committed. Breaking changes mean a major version.
Getting Started
Getting started is the same as it was during beta:
Install-Package DGates.AwsSecretsManager
Startup is one factory call; retrieval is one typed call:
var secrets = SecretsManagerServiceFactory.Create(new SecretsManagerSettings
{
Region = "us-west-2",
CacheTtl = TimeSpan.FromMinutes(15)
});
var secret = await secrets.GetSecretAsync<MySecret>("dev/MyApp/MySecret");
The repository ships with a LocalStack docker-compose.yml and a JSON fallback path for Docker-free environments, so you can try everything locally without an AWS account. The first post covers both in detail, and the examples repo has a full MVC 5 app wired up end to end.
What's Next
Cache stampede protection, serializer abstraction, and rotation handling are all candidates for the 1.x line, but the issue tracker remains the source of truth for what's actually planned.
Building this against a real MVC 5 application shaped this release. If you're using it in a legacy codebase, I'd genuinely like to hear what works well — and what doesn't. That kind of feedback will shape where the library goes next.
Top comments (0)