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..52cb77a95 --- /dev/null +++ b/teams.md/src/pages/templates/in-depth-guides/dependency-injection.mdx @@ -0,0 +1,27 @@ +--- +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 + +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 + +