m365-agents-dotnet
作者: microsoft
使用 Microsoft.Agents SDK 构建适用于 Microsoft 365、Teams 和 Copilot Studio 的企业级代理,支持 ASP.NET Core 托管、代理路由和基于 MSAL 的身份验证。
npx skills add https://github.com/microsoft/agent-skills --skill m365-agents-dotnetMicrosoft 365 Agents SDK (.NET)
Overview
Build enterprise agents for Microsoft 365, Teams, and Copilot Studio using the Microsoft.Agents SDK with ASP.NET Core hosting, agent routing, and MSAL-based authentication.
Before implementation
- Use the microsoft-docs MCP to verify the latest APIs for AddAgent, AgentApplication, and authentication options.
- Confirm package versions in NuGet for the Microsoft.Agents.* packages you plan to use.
Installation
dotnet add package Microsoft.Agents.Hosting.AspNetCore
dotnet add package Microsoft.Agents.Authentication.Msal
dotnet add package Microsoft.Agents.Storage
dotnet add package Microsoft.Agents.CopilotStudio.Client
dotnet add package Microsoft.Identity.Client.Extensions.Msal
Configuration (appsettings.json)
{
"TokenValidation": {
"Enabled": true,
"Audiences": ["{{ClientId}}"],
"TenantId": "{{TenantId}}"
},
"AgentApplication": {
"StartTypingTimer": false,
"RemoveRecipientMention": false,
"NormalizeMentions": false
},
"Connections": {
"ServiceConnection": {
"Settings": {
"AuthType": "ClientSecret",
"ClientId": "{{ClientId}}",
"ClientSecret": "{{ClientSecret}}",
"AuthorityEndpoint": "https://login.microsoftonline.com/{{TenantId}}",
"Scopes": ["https://api.botframework.com/.default"]
}
}
},
"ConnectionsMap": [
{
"ServiceUrl": "*",
"Connection": "ServiceConnection"
}
],
"CopilotStudioClientSettings": {
"DirectConnectUrl": "",
"EnvironmentId": "",
"SchemaName": "",
"TenantId": "",
"AppClientId": "",
"AppClientSecret": ""
}
}
Core Workflow: ASP.NET Core agent host
using Microsoft.Agents.Builder;
using Microsoft.Agents.Hosting.AspNetCore;
using Microsoft.Agents.Storage;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpClient();
builder.AddAgentApplicationOptions();
builder.AddAgent<MyAgent>();
builder.Services.AddSingleton<IStorage, MemoryStorage>();
builder.Services.AddControllers();
builder.Services.AddAgentAspNetAuthentication(builder.Configuration);
WebApplication app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapGet("/", () => "Microsoft Agents SDK Sample");
var incomingRoute = app.MapPost("/api/messages",
async (HttpRequest request, HttpResponse response, IAgentHttpAdapter adapter, IAgent agent, CancellationToken ct) =>
{
await adapter.ProcessAsync(request, response, agent, ct);
});
if (!app.Environment.IsDevelopment())
{
incomingRoute.RequireAuthorization();
}
else
{
app.Urls.Add("http://localhost:3978");
}
app.Run();
AgentApplication routing
using Microsoft.Agents.Builder;
using Microsoft.Agents.Builder.App;
using Microsoft.Agents.Builder.State;
using Microsoft.Agents.Core.Models;
using System;
using System.Threading;
using System.Threading.Tasks;
public sealed class MyAgent : AgentApplication
{
public MyAgent(AgentApplicationOptions options) : base(options)
{
OnConversationUpdate(ConversationUpdateEvents.MembersAdded, WelcomeAsync);
OnActivity(ActivityTypes.Message, OnMessageAsync, rank: RouteRank.Last);
OnTurnError(OnTurnErrorAsync);
}
private static async Task WelcomeAsync(ITurnContext turnContext, ITurnState turnState, CancellationToken ct)
{
foreach (ChannelAccount member in turnContext.Activity.MembersAdded)
{
if (member.Id != turnContext.Activity.Recipient.Id)
{
await turnContext.SendActivityAsync(
MessageFactory.Text("Welcome to the agent."),
ct);
}
}
}
private static async Task OnMessageAsync(ITurnContext turnContext, ITurnState turnState, CancellationToken ct)
{
await turnContext.SendActivityAsync(
MessageFactory.Text($"You said: {turnContext.Activity.Text}"),
ct);
}
private static async Task OnTurnErrorAsync(
ITurnContext turnContext,
ITurnState turnState,
Exception exception,
CancellationToken ct)
{
await turnState.Conversation.DeleteStateAsync(turnContext, ct);
var endOfConversation = Activity.CreateEndOfConversationActivity();
endOfConversation.Code = EndOfConversationCodes.Error;
endOfConversation.Text = exception.Message;
await turnContext.SendActivityAsync(endOfConversation, ct);
}
}
Copilot Studio direct-to-engine client
DelegatingHandler for token acquisition (interactive flow)
using System.Net.Http.Headers;
using Microsoft.Agents.CopilotStudio.Client;
using Microsoft.Identity.Client;
internal sealed class AddTokenHandler : DelegatingHandler
{
private readonly SampleConnectionSettings _settings;
public AddTokenHandler(SampleConnectionSettings settings) : base(new HttpClientHandler())
{
_settings = settings;
}
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
if (request.Headers.Authorization is null)
{
string[] scopes = [CopilotClient.ScopeFromSettings(_settings)];
IPublicClientApplication app = PublicClientApplicationBuilder
.Create(_settings.AppClientId)
.WithAuthority(AadAuthorityAudience.AzureAdMyOrg)
.WithTenantId(_settings.TenantId)
.WithRedirectUri("http://localhost")
.Build();
AuthenticationResult authResponse;
try
{
var account = (await app.GetAccountsAsync()).FirstOrDefault();
authResponse = await app.AcquireTokenSilent(scopes, account).ExecuteAsync(cancellationToken);
}
catch (MsalUiRequiredException)
{
authResponse = await app.AcquireTokenInteractive(scopes).ExecuteAsync(cancellationToken);
}
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authResponse.AccessToken);
}
return await base.SendAsync(request, cancellationToken);
}
}
Console host with CopilotClient
using Microsoft.Agents.CopilotStudio.Client;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
var settings = new SampleConnectionSettings(
builder.Configuration.GetSection("CopilotStudioClientSettings"));
builder.Services.AddHttpClient("mcs").ConfigurePrimaryHttpMessageHandler(() =>
{
return new AddTokenHandler(settings);
});
builder.Services
.AddSingleton(settings)
.AddTransient<CopilotClient>(sp =>
{
var logger = sp.GetRequiredService<ILoggerFactory>().CreateLogger<CopilotClient>();
return new CopilotClient(settings, sp.GetRequiredService<IHttpClientFactory>(), logger, "mcs");
});
IHost host = builder.Build();
var client = host.Services.GetRequiredService<CopilotClient>();
await foreach (var activity in client.StartConversationAsync(emitStartConversationEvent: true))
{
Console.WriteLine(activity.Type);
}
await foreach (var activity in client.AskQuestionAsync("Hello!", null))
{
Console.WriteLine(activity.Type);
}
Best Practices
- Use AgentApplication subclasses to centralize routing and error handling.
- Use MemoryStorage only for development; use persisted storage in production.
- Enable TokenValidation in production and require authorization on /api/messages.
- Keep auth secrets in configuration providers (Key Vault, managed identity, env vars).
- Reuse HttpClient from IHttpClientFactory and cache MSAL tokens.
- Prefer async handlers and pass CancellationToken to SDK calls.
Reference Links
来自 microsoft 的更多技能
oss-growth
microsoft
OSS增长黑客角色
official
microsoft-foundry
microsoft
端到端部署、评估和管理Foundry代理:Docker构建、ACR推送、托管/提示代理创建、容器启动、批量评估、持续评估、提示优化工作流、agent.yaml、从追踪中整理数据集。用途:将代理部署到Foundry、托管代理、创建代理、调用代理、评估代理、运行批量评估、持续评估、持续监控、持续评估状态、优化提示、改进提示、提示优化器、优化代理指令、改进代理...
officialdevelopmentdevops
azure-ai
microsoft
用于Azure AI:搜索、语音、OpenAI、文档智能。支持搜索、向量/混合搜索、语音转文字、文字转语音、转录、OCR。适用场景:AI搜索、查询搜索、向量搜索、混合搜索、语义搜索、语音转文字、文字转语音、转录、OCR、文字转语音。
officialdevelopmentapi
azure-deploy
microsoft
对已准备好的应用程序执行Azure部署,这些程序需包含现有的.azure/deployment-plan.md和基础设施文件。当用户要求创建新应用程序时,请勿使用此技能——应改用azure-prepare。此技能运行azd up、azd deploy、terraform apply和az deployment命令,并内置错误恢复机制。需要来自azure-prepare的.azure/deployment-plan.md以及来自azure-validate的已验证状态。适用场景:"运行azd up"、"运行azd deploy"、"执行部署"...
officialdevopsaws
azure-storage
microsoft
Azure存储服务,包括Blob存储、文件共享、队列存储、表存储和Data Lake。解答关于存储访问层(热、冷、冷、归档)的问题,说明各层的使用场景及对比。提供对象存储、SMB文件共享、异步消息传递、NoSQL键值存储和大数据分析。包含生命周期管理。用途:Blob存储、文件共享、队列存储、表存储、Data Lake、上传文件、下载Blob、存储账户、访问层等。
officialdevelopmentdatabase
azure-diagnostics
microsoft
使用AppLens、Azure Monitor、资源健康和安全分类调试Azure生产问题。适用场景:调试生产问题、排查应用服务、应用服务CPU过高、应用服务部署失败、排查容器应用、排查函数、排查AKS、kubectl无法连接、kube-system/CoreDNS故障、Pod挂起、CrashLoop、节点未就绪、升级失败、分析日志、KQL、洞察、镜像拉取失败、冷启动问题、健康探测失败……
officialdevopsdevelopment
azure-prepare
microsoft
为Azure应用准备部署(基础设施Bicep/Terraform、azure.yaml、Dockerfile)。用于创建/现代化或创建+部署;不用于跨云迁移(使用azure-cloud-migrate)。请勿用于:copilot-sdk应用(使用azure-hosted-copilot-sdk)。适用场景:"创建应用"、"构建Web应用"、"创建API"、"创建无服务器HTTP API"、"创建前端"、"创建后端"、"构建服务"、"现代化应用"、"更新应用"、"添加身份验证"、"添加缓存"、"托管在Azure上"、"创建并...
officialdevelopmentdevops
azure-validate
microsoft
部署前对Azure就绪状态进行验证。对配置、基础设施(Bicep或Terraform)、RBAC角色分配、托管标识权限及先决条件进行深度检查,然后再部署。适用场景:验证我的应用、检查部署就绪状态、运行预检、验证配置、检查是否可部署、验证azure.yaml、验证Bicep、部署前测试、排查部署错误、验证Azure Functions、验证函数应用、验证无服务器...
officialdevopstesting