csharp-scripts
Run file-based C# apps with the .NET CLI when the user explicitly wants C#/.NET code without creating a project. Use for C# language/API experiments, one-file…
DO NOT USE when the target already consumes an injected interface or built-in abstraction such as IFileSystem or TimeProvider, even if the request says "generate a wrapper"; no new wrapper is needed. Use only when C# source calls an ambient/static dependency and no injectable
$ npx -y skills add dotnet/skills --skill generate-testability-wrappers --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/generate-testability-wrappersContext preview
The summary Claude sees to decide when to auto-load this skill.
DO NOT USE when the target already consumes an injected interface or built-in abstraction such as IFileSystem or TimeProvider, even if the request says "generate a wrapper"; no new wrapper is needed. Use only when C# source calls an ambient/static dependency and no injectable
name: generate-testability-wrappers description: > DO NOT USE when the target already consumes an injected interface or built-in abstraction such as IFileSystem or TimeProvider, even if the request says "generate a wrapper"; no new wrapper is needed. Use only when C# source calls an ambient/static dependency and no injectable seam exists: first-time TimeProvider, IHttpClientFactory, or System.IO.Abstractions adoption; minimal Environment/Console/Process wrappers; IProcessRunner; DI registration; or an ambient seam that preserves a static API. Exclude static detection (detect-static-dependencies), migration to an existing/registered abstraction (migrate-static-to-wrapper), one blocked behavior plus deterministic tests (testability-obstacle), and general interface design. license: MIT
Generate wrapper interfaces, default implementations, and DI service registration code for untestable static dependencies. For statics that already have .NET built-in abstractions (`TimeProvider`, `IHttpClientFactory`), guide adoption of the built-in. For statics without built-in alternatives, generate custom minimal wrappers.
If the target already consumes an injected interface or built-in abstraction, stop: do not add a second wrapper, project, registration, or test around that seam.
> A missing DI package does not by itself force an ambient seam. For an > instantiable class, prefer constructor injection and compose it explicitly or > show the requested registration. Use Step 5 when the API is static and its > signatures must stay static, or when the user explicitly forbids caller > construction/DI changes.
| Input | Required | Description | |-------|----------|-------------| | Static category | Yes | Which category: `time`, `filesystem`, `environment`, `network`, `console`, `process` | | Target framework | Yes | The `TargetFramework` from `.csproj` (affects which built-in abstractions exist) | | Composition | No | Existing DI framework, explicit/manual construction, or immutable static API | | Namespace | No | Target namespace for generated wrapper code |
Based on the category and target framework:
| Category | .NET 8+ | .NET 6-7 | .NET Framework | |----------|---------|----------|----------------| | Time | `TimeProvider` (built-in) | `TimeProvider` via `Microsoft.Bcl.TimeProvider` NuGet | Custom `ISystemClock` | | File system | `System.IO.Abstractions` (NuGet) | Same | Same | | HTTP | `IHttpClientFactory` (built-in) | Same | Same | | Environment | Custom `IEnvironmentProvider` | Same | Same | | Console | Custom `IConsole` | Same | Same | | Process | Custom `IProcessRunner` | Same | Same |
The table picks *which abstraction*. How it reaches the code under test is a separate axis:
object manually;
Check for a host builder, `IServiceCollection`, existing registrations, and construction sites. Do not infer "must remain static" merely because the project currently has no container.
No wrapper code needed. Complete all four parts: production registration, constructor injection, a `FakeTimeProvider` test, and the testing package.
1. Register in DI:
builder.Services.AddSingleton(TimeProvider.System);
2. Inject into classes:
public class OrderProcessor(TimeProvider timeProvider)
{
public bool IsExpired(Order order)
=> timeProvider.GetUtcNow() > order.ExpiresAt;
}3. Test with `FakeTimeProvider`:
// Requires Microsoft.Extensions.TimeProvider.Testing NuGet var fakeTime = new FakeTimeProvider(new DateTimeOffset(2026, 1, 15, 0, 0, 0, TimeSpan.Zero)); var processor = new OrderProcessor(fakeTime); fakeTime.Advance(TimeSpan.FromDays(1)); Assert.True(processor.IsExpired(order));
The assertion must prove a time-dependent result after the fake is pinned or advanced. Merely constructing `FakeTimeProvider` is not a test. When the project has no container but the target is an instantiable class, inject `TimeProvider` anyway and show explicit production construction with `TimeProvider.System`; do not replace it with a custom static clock.
Before calling the adoption complete, verify the repository contains or the answer supplies every required artifact: the testing package reference, the production composition/registration, every affected constructor call, and a runnable fake-time test. A code fragment that omits one of those integration points is guidance, not a completed adoption.
Guide: install `Microsoft.Bcl.TimeProvider` NuGet. Same API as above.
No wrapper code needed. Register a typed client via `builder.Services.AddHttpClient<MyService>()` and inject `HttpClient` directly into the class constructor. Preserve cancellation by passing the caller's token to the HTTP operation.
For tests, provide a complete fake `HttpMessageHandler` whose `SendAsync` returns a deterministic `HttpResponseMessage`, construct `Ht
This repository contains the .NET team's curated set of portable skills and host-specific custom agents for coding agents. For information about the Agent Skills standard, see agentskills.io.
Repo: dotnet/skills
Run file-based C# apps with the .NET CLI when the user explicitly wants C#/.NET code without creating a project. Use for C# language/API experiments, one-file…
Correctly call native (C/C++) libraries from .NET using P/Invoke and LibraryImport. Covers function signatures, string marshalling, memory lifetime,…
Set up NuGet trusted publishing (OIDC) on a GitHub Actions repo — replaces long-lived API keys with short-lived tokens. USE FOR: trusted publishing, NuGet…
Design, implement, optimize, and review SIMD code in .NET. USE FOR: vectorizing scalar loops with TensorPrimitives, Vector64/128/256/512, or platform hardware…
Guides technology selection and implementation of AI and ML features in .NET 8+ applications using ML.NET, Microsoft.Extensions.AI (MEAI), Microsoft Agent…
Configure OpenTelemetry distributed tracing, metrics, and logging in ASP.NET Core using the .NET OpenTelemetry SDK. Use when adding observability, setting up…