Announcing Teams SDK for .NET 2.1 Preview
Build Agent 365 solutions with the Teams SDK for .NET 2.1 preview, available today:
dotnet add package Microsoft.Teams.Apps --prerelease
Here's what changes for your Teams bot apps:
- Your app is just an ASP.NET Core app. Standard DI,
ILogger, andIConfigurationthroughout, with typed activity handlers and a rich context object. A working bot is about 15 lines. - Run your bot as an AI teammate with its own identity. The SDK supports agentic identities from Agent 365, so your bot can act as the AI teammate with their permissions, no extra plumbing needed.
- Migrate your existing Bot Framework v4 bot in two lines. A compatibility package runs your existing
IBotimplementation on the new infrastructure unchanged, so you can adopt all new features at your own pace, including Agentic scenarios.
Coming from Teams SDK 2.0? Most of the API surface is unchanged โ
context.Send(),context.Reply(),context.Log, handler registration, andApp.Builder()all work as before. See what changed for the short list of changes.
Native ASP.NET Core Integrationโ
The 2.1 preview is built around the patterns .NET developers already know. All services register through AddTeamsBotApplication() โ Dependency injection, Logging, and Configuration are all standard. Incoming and outgoing authentication is built on MSAL, with support for client secrets, managed identities, and federated identity credentials.
Here's a minimal bot that handles messages in about 15 lines:
using Microsoft.Teams.Apps;
WebApplicationBuilder builder = WebApplication.CreateSlimBuilder(args);
builder.Services.AddTeamsBotApplication();
WebApplication app = builder.Build();
TeamsBotApplication teams = app.UseTeamsBotApplication();
teams.OnMessage(async (context, cancellationToken) =>
{
await context.SendActivityAsync($"You said: {context.Activity.Text}", cancellationToken);
});
app.Run();
AddTeamsBotApplication() registers everything the SDK needs into DI. UseTeamsBotApplication() wires it into the ASP.NET Core pipeline. From there, you register handlers for the activity types you care about.
Authentication is configured through the standard AzureAd section in appsettings.json:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "your-tenant-id",
"ClientId": "your-client-id",
"ClientCredentials": [
{
"SourceType": "ClientSecret",
"ClientSecret": "your-client-secret"
}
]
}
}
The SDK auto-detects the credential type based on which fields are present โ client secrets, system-assigned managed identities, user-assigned managed identities, and federated identity credentials all work from this same config block with no code changes between them.
To run the application listening on a given port:
dotnet run -- --urls http://*:3978
Agentic Identityโ
With Agent 365, your bot can run as an AI teammate โ a first-class identity in Microsoft 365 with its own mailbox, Teams presence, directory entry, and manager relationship. People @mention it, email it, and invite it to meetings, just like a human colleague.
This changes how your bot interacts with APIs. A traditional bot calls APIs with its own app permissions. An AI teammate can call APIs with its own identity โ scoped to what they can access, with actions attributed to them in audit logs.
If you need to check whether you're in an agentic context โ for logging or conditional logic โ pull the identity off the activity Recipient object:
teams.OnMessage(async (context, cancellationToken) =>
{
var agenticIdentity = context.Activity.Recipient?.GetAgenticIdentity();
if (agenticIdentity is not null)
{
context.Log.Info(
$"Acting on behalf of user {agenticIdentity.AgenticUserId} " +
$"via app {agenticIdentity.AgenticAppId}");
}
// context.Api calls automatically use the right permissions
// whether or not an agentic identity is present
await context.SendActivityAsync(
$"You said: {context.Activity.Text}",
cancellationToken);
});
To get started with agentic scenarios, configure your app registration for Agent 365. For the deeper conceptual background, see the Agent 365 identity documentation.
Migration from Bot Framework v4โ
If you have an existing Bot Framework v4 bot, you don't need to rewrite it. The Microsoft.Teams.Apps.BotBuilder package provides a compatibility layer that lets your current IBot implementation run on the new SDK infrastructure with minimal changes.
Your bot's business logic stays exactly the same โ ConversationState, UserState, Dialogs, WaterfallDialogs, SSO, and Middleware all work as-is. Only the hosting and infrastructure layer changes.
Drop-in migrationโ
Replace NuGet packagesโ
<!-- Remove this -->
<PackageReference Include="Microsoft.Bot.Builder.Integration.AspNet.Core" Version="4.22.3" />
<!-- Add this -->
<PackageReference Include="Microsoft.Teams.Apps.BotBuilder" Version="1.0.*" />
Update your startup codeโ
Your IBot implementation stays untouched. Only the service registration changes:
Before (Bot Framework v4):
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();
builder.Services.AddTransient<IBot, EchoBot>();
var app = builder.Build();
app.MapControllers();
app.Run();
After (Teams SDK 2.1 compatibility):
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Teams.Apps.BotBuilder;
var builder = WebApplication.CreateBuilder(args);
builder.AddTeamsBotFrameworkHttpAdapter();
builder.Services.AddTransient<IBot, EchoBot>();
var app = builder.Build();
app.MapPost("/api/messages", async (IBotFrameworkHttpAdapter adapter, IBot bot, HttpRequest request, HttpResponse response, CancellationToken ct)
=> await adapter.ProcessAsync(request, response, bot, ct));
app.Run();
Update your configurationโ
Replace the flat Bot Framework keys with the standard AzureAd section:
Before:
{
"MicrosoftAppId": "your-client-id",
"MicrosoftAppPassword": "your-client-secret",
"MicrosoftAppTenantId": "your-tenant-id"
}
After:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "your-tenant-id",
"ClientId": "your-client-id",
"ClientCredentials": [
{
"SourceType": "ClientSecret",
"ClientSecret": "your-client-secret"
}
]
}
}
That's it. Run dotnet run and your bot responds to the same messages on the same endpoint.
Key API differencesโ
| Bot Framework v4 | Teams SDK 2.1 | Notes |
|---|---|---|
turnContext.SendActivityAsync(MessageFactory.Text("hi")) | context.Send("hi", ct) | Convenience method on context |
ITurnContext<IMessageActivity> | Context<MessageActivity> | Strongly typed context |
MessageFactory.Text("hi") | new MessageActivity("hi") | Direct construction |
TeamsInfo | replace with TeamsApiClient | |
turnContext.Activity.CreateReply("text") | context.Reply("text", ct) | Auto-quotes the inbound message |
Migration from Teams SDK 2.0โ
Most of your code works unchanged. Here's the short list of changes.
API changesโ
context.Ref removed โ Use context.Activity.Conversation directly instead of context.Ref.Conversation.
OAuth events moved to per-flow callbacks:
// Old
teams.OnSignIn(async (_, @event, cancellationToken) => { ... });
// New
var flow = teams.GetOAuthFlow("graph");
flow.OnSignInComplete(async (context, token, cancellationToken) => { ... });
Namespace changes โ Activity types moved from Microsoft.Teams.Api.Activities to Microsoft.Teams.Apps.Schema. Member access (.Text, .From, .Conversation) stays the same โ only using statements need updating.
Packages no longer availableโ
The 2.1 preview consolidates into three packages. The following 2.0 packages have no equivalent and must be replaced:
| Removed package | Alternative |
|---|---|
Microsoft.Teams.AI / Microsoft.Teams.AI.Models.OpenAI | Microsoft.Extensions.AI |
Microsoft.Teams.Cards | Use TeamsActivityBuilder with AddAdaptiveCardAttachment() |
Microsoft.Teams.Extensions.Graph | Microsoft.Graph |
Microsoft.Teams.Apps.Testing | Use standard .NET DI mocking |
Microsoft.Teams.Common (logging, HTTP) | Use Microsoft.Extensions.Logging and HttpClient via DI |
Microsoft.Teams.Plugins.* | Plugin architecture removed โ use standard ASP.NET Core middleware and DI |
For the full list of API changes, see the Migration Guide.
What You Can Build Todayโ
The preview supports the following scenarios:
- Messages โ handling, regex routing, updates, deletes, reactions
- Adaptive Cards โ action submissions with typed value access
- Task modules โ fetch and submit dialogs
- Message extensions โ search queries
- OAuth and SSO โ per-flow sign-in with automatic SSO
- Conversation events โ members added/removed, install/uninstall
- Streaming โ progressive message updates with rate limiting
- Proactive messaging โ send messages and replies outside of a turn
- Agentic identity โ act on behalf of users with their permissions
- Targeted messages โ messages visible only to a specific user
Roadmapโ
We're actively working on completing the integration with Agent 365 for the GA release. This includes full support for agentic identity flows, lifecycle events, and alignment with the broader Agent 365 ecosystem such as OpenTelemetry integration for enhanced observability.
We'd love your feedback on the preview. File issues and feature requests on the GitHub repository.