Skip to main content

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:

Coming from Teams SDK 2.0? Most of the API surface is unchanged โ€” context.Send(), context.Reply(), context.Log, handler registration, and App.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.

Traditional bot โ€” acts as itselfAI teammate โ€” acts with its own identityHuman userYour botas an appMicrosoft GraphHuman userYour botas AI teammateMicrosoft Graphsends messageapp permissionssends messageAI Teammate's permissions

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 v4Teams SDK 2.1Notes
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
TeamsInforeplace 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 packageAlternative
Microsoft.Teams.AI / Microsoft.Teams.AI.Models.OpenAIMicrosoft.Extensions.AI
Microsoft.Teams.CardsUse TeamsActivityBuilder with AddAdaptiveCardAttachment()
Microsoft.Teams.Extensions.GraphMicrosoft.Graph
Microsoft.Teams.Apps.TestingUse 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.