From fe269ee75b19ca10d1363adb5dafb6b00b15193f Mon Sep 17 00:00:00 2001 From: Rajan Date: Fri, 10 Apr 2026 12:56:14 -0400 Subject: [PATCH 1/2] docs: add dependency injection guide for minimal API pattern New in-depth guide covering DI access in callback handlers: - Closure capture pattern for singleton/transient services - CreateScope() for scoped services (DbContext etc.) - Migration note for developers coming from controller pattern - Link from BotBuilder integration migration guide Addresses microsoft/teams.net#420 Co-Authored-By: Claude Opus 4.6 (1M context) --- .../dependency-injection/csharp.incl.md | 80 +++++++++++++++++++ .../botbuilder/integration/csharp.incl.md | 6 +- .../in-depth-guides/dependency-injection.mdx | 26 ++++++ 3 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 teams.md/src/components/include/in-depth-guides/dependency-injection/csharp.incl.md create mode 100644 teams.md/src/pages/templates/in-depth-guides/dependency-injection.mdx diff --git a/teams.md/src/components/include/in-depth-guides/dependency-injection/csharp.incl.md b/teams.md/src/components/include/in-depth-guides/dependency-injection/csharp.incl.md new file mode 100644 index 000000000..0f3ac48a5 --- /dev/null +++ b/teams.md/src/components/include/in-depth-guides/dependency-injection/csharp.incl.md @@ -0,0 +1,80 @@ + + +### Accessing DI Services in Handlers + +The Teams SDK uses the minimal API callback pattern. Services registered in `builder.Services` are available via `app.Services` after `builder.Build()`. Capture them in your handler closures: + +```csharp +var builder = WebApplication.CreateBuilder(args); +builder.AddTeams(); + +// Register your services +builder.Services.AddSingleton(); + +var app = builder.Build(); +var teams = app.UseTeams(); + +// Resolve from DI and capture in the closure +var myService = app.Services.GetRequiredService(); + +teams.OnMessage(async (context, cancellationToken) => +{ + // myService is captured from the outer scope + var result = await myService.ProcessAsync(context.Activity.Text); + await context.Send(result, cancellationToken); +}); + +app.Run(); +``` + +This is the same pattern used throughout ASP.NET Core minimal APIs. + + + +### Scoped Services (e.g., DbContext) + +Scoped services are created once per scope. In a controller, ASP.NET Core creates a scope per request automatically. In callbacks, you create the scope yourself: + +```csharp +var sp = app.Services; + +teams.OnMessage(async (context, cancellationToken) => +{ + using var scope = sp.CreateScope(); + var dbContext = scope.ServiceProvider.GetRequiredService(); + // dbContext is scoped to this request + await dbContext.Logs.AddAsync(new LogEntry { Text = context.Activity.Text }); + await dbContext.SaveChangesAsync(cancellationToken); +}); +``` + +:::warning +Do not resolve scoped services directly from `app.Services` — this throws `InvalidOperationException` at runtime. Always use `CreateScope()`. +::: + + + +### Coming from Controllers? + +If you previously used controller-based bots, you're used to constructor injection: + +```csharp +public class MyBot : ActivityHandler +{ + private readonly IMyService _service; + + public MyBot(IMyService service) + { + _service = service; + } +} +``` + +In the callback pattern, there's no class and no constructor. You resolve services from `app.Services` and capture them in closures. The result is the same — your handler has access to the service — the mechanism is different. + + + +### See Also + +- [Samples.Lights](https://github.com/microsoft/teams.net/blob/main/Samples/Samples.Lights/Program.cs#L18) — captures a prompt factory from DI +- [Middleware guide](/in-depth-guides/observability/middleware) — cross-cutting concerns via `app.Use()` diff --git a/teams.md/src/components/include/migrations/botbuilder/integration/csharp.incl.md b/teams.md/src/components/include/migrations/botbuilder/integration/csharp.incl.md index 0ac109b3f..8a747bdb4 100644 --- a/teams.md/src/components/include/migrations/botbuilder/integration/csharp.incl.md +++ b/teams.md/src/components/include/migrations/botbuilder/integration/csharp.incl.md @@ -80,4 +80,8 @@ ``` - \ No newline at end of file + + +:::info +**Dependency Injection:** In the controller pattern, services are injected via the constructor. In the Teams SDK callback pattern, resolve services from `app.Services` after `builder.Build()` and capture them in your handler closures. See [Dependency Injection](/in-depth-guides/dependency-injection) for details and examples. +::: \ No newline at end of file diff --git a/teams.md/src/pages/templates/in-depth-guides/dependency-injection.mdx b/teams.md/src/pages/templates/in-depth-guides/dependency-injection.mdx new file mode 100644 index 000000000..84838750c --- /dev/null +++ b/teams.md/src/pages/templates/in-depth-guides/dependency-injection.mdx @@ -0,0 +1,26 @@ +--- +sidebar_position: 6 +title: 'Dependency Injection' +summary: Access DI services in minimal API handlers using closure capture and service scoping patterns. +--- + +# Dependency Injection + +The Teams SDK uses the minimal API callback pattern. This guide covers how to access +services registered in your DI container from within handler callbacks. + +## Accessing Services + + + +## Scoped Services + + + +## Coming from Controllers? + + + +## See Also + + From 163c291b1b7d625df3ca086f6627bb8b8131912e Mon Sep 17 00:00:00 2001 From: Rajan Date: Fri, 10 Apr 2026 14:09:53 -0400 Subject: [PATCH 2/2] docs: restrict DI guide to csharp only (prevents build failure) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The docs generator fails in production mode if language-specific include files are missing. Added languages: [csharp] frontmatter to prevent generation for TypeScript/Python (no DI guide for those yet — they use different patterns). Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/pages/templates/in-depth-guides/dependency-injection.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/teams.md/src/pages/templates/in-depth-guides/dependency-injection.mdx b/teams.md/src/pages/templates/in-depth-guides/dependency-injection.mdx index 84838750c..52cb77a95 100644 --- a/teams.md/src/pages/templates/in-depth-guides/dependency-injection.mdx +++ b/teams.md/src/pages/templates/in-depth-guides/dependency-injection.mdx @@ -2,6 +2,7 @@ sidebar_position: 6 title: 'Dependency Injection' summary: Access DI services in minimal API handlers using closure capture and service scoping patterns. +languages: [csharp] --- # Dependency Injection