|
Add this skill
npx mdskills install sickn33/m365-agents-dotnetComprehensive SDK guide with complete code examples, auth patterns, and production practices
1---2name: m365-agents-dotnet3description: |4 Microsoft 365 Agents SDK for .NET. Build multichannel agents for Teams/M365/Copilot Studio with ASP.NET Core hosting, AgentApplication routing, and MSAL-based auth. Triggers: "Microsoft 365 Agents SDK", "Microsoft.Agents", "AddAgentApplicationOptions", "AgentApplication", "AddAgentAspNetAuthentication", "Copilot Studio client", "IAgentHttpAdapter".5package: Microsoft.Agents.Hosting.AspNetCore, Microsoft.Agents.Authentication.Msal, Microsoft.Agents.CopilotStudio.Client6---78# Microsoft 365 Agents SDK (.NET)910## Overview11Build 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.1213## Before implementation14- Use the microsoft-docs MCP to verify the latest APIs for AddAgent, AgentApplication, and authentication options.15- Confirm package versions in NuGet for the Microsoft.Agents.* packages you plan to use.1617## Installation1819```bash20dotnet add package Microsoft.Agents.Hosting.AspNetCore21dotnet add package Microsoft.Agents.Authentication.Msal22dotnet add package Microsoft.Agents.Storage23dotnet add package Microsoft.Agents.CopilotStudio.Client24dotnet add package Microsoft.Identity.Client.Extensions.Msal25```2627## Configuration (appsettings.json)2829```json30{31 "TokenValidation": {32 "Enabled": true,33 "Audiences": [34 "{{ClientId}}"35 ],36 "TenantId": "{{TenantId}}"37 },38 "AgentApplication": {39 "StartTypingTimer": false,40 "RemoveRecipientMention": false,41 "NormalizeMentions": false42 },43 "Connections": {44 "ServiceConnection": {45 "Settings": {46 "AuthType": "ClientSecret",47 "ClientId": "{{ClientId}}",48 "ClientSecret": "{{ClientSecret}}",49 "AuthorityEndpoint": "https://login.microsoftonline.com/{{TenantId}}",50 "Scopes": [51 "https://api.botframework.com/.default"52 ]53 }54 }55 },56 "ConnectionsMap": [57 {58 "ServiceUrl": "*",59 "Connection": "ServiceConnection"60 }61 ],62 "CopilotStudioClientSettings": {63 "DirectConnectUrl": "",64 "EnvironmentId": "",65 "SchemaName": "",66 "TenantId": "",67 "AppClientId": "",68 "AppClientSecret": ""69 }70}71```7273## Core Workflow: ASP.NET Core agent host7475```csharp76using Microsoft.Agents.Builder;77using Microsoft.Agents.Hosting.AspNetCore;78using Microsoft.Agents.Storage;79using Microsoft.AspNetCore.Builder;80using Microsoft.AspNetCore.Http;81using Microsoft.Extensions.DependencyInjection;82using Microsoft.Extensions.Hosting;8384var builder = WebApplication.CreateBuilder(args);8586builder.Services.AddHttpClient();87builder.AddAgentApplicationOptions();88builder.AddAgent<MyAgent>();89builder.Services.AddSingleton<IStorage, MemoryStorage>();9091builder.Services.AddControllers();92builder.Services.AddAgentAspNetAuthentication(builder.Configuration);9394WebApplication app = builder.Build();9596app.UseAuthentication();97app.UseAuthorization();9899app.MapGet("/", () => "Microsoft Agents SDK Sample");100101var incomingRoute = app.MapPost("/api/messages",102 async (HttpRequest request, HttpResponse response, IAgentHttpAdapter adapter, IAgent agent, CancellationToken ct) =>103 {104 await adapter.ProcessAsync(request, response, agent, ct);105 });106107if (!app.Environment.IsDevelopment())108{109 incomingRoute.RequireAuthorization();110}111else112{113 app.Urls.Add("http://localhost:3978");114}115116app.Run();117```118119## AgentApplication routing120121```csharp122using Microsoft.Agents.Builder;123using Microsoft.Agents.Builder.App;124using Microsoft.Agents.Builder.State;125using Microsoft.Agents.Core.Models;126using System;127using System.Threading;128using System.Threading.Tasks;129130public sealed class MyAgent : AgentApplication131{132 public MyAgent(AgentApplicationOptions options) : base(options)133 {134 OnConversationUpdate(ConversationUpdateEvents.MembersAdded, WelcomeAsync);135 OnActivity(ActivityTypes.Message, OnMessageAsync, rank: RouteRank.Last);136 OnTurnError(OnTurnErrorAsync);137 }138139 private static async Task WelcomeAsync(ITurnContext turnContext, ITurnState turnState, CancellationToken ct)140 {141 foreach (ChannelAccount member in turnContext.Activity.MembersAdded)142 {143 if (member.Id != turnContext.Activity.Recipient.Id)144 {145 await turnContext.SendActivityAsync(146 MessageFactory.Text("Welcome to the agent."),147 ct);148 }149 }150 }151152 private static async Task OnMessageAsync(ITurnContext turnContext, ITurnState turnState, CancellationToken ct)153 {154 await turnContext.SendActivityAsync(155 MessageFactory.Text($"You said: {turnContext.Activity.Text}"),156 ct);157 }158159 private static async Task OnTurnErrorAsync(160 ITurnContext turnContext,161 ITurnState turnState,162 Exception exception,163 CancellationToken ct)164 {165 await turnState.Conversation.DeleteStateAsync(turnContext, ct);166167 var endOfConversation = Activity.CreateEndOfConversationActivity();168 endOfConversation.Code = EndOfConversationCodes.Error;169 endOfConversation.Text = exception.Message;170 await turnContext.SendActivityAsync(endOfConversation, ct);171 }172}173```174175## Copilot Studio direct-to-engine client176177### DelegatingHandler for token acquisition (interactive flow)178179```csharp180using System.Net.Http.Headers;181using Microsoft.Agents.CopilotStudio.Client;182using Microsoft.Identity.Client;183184internal sealed class AddTokenHandler : DelegatingHandler185{186 private readonly SampleConnectionSettings _settings;187188 public AddTokenHandler(SampleConnectionSettings settings) : base(new HttpClientHandler())189 {190 _settings = settings;191 }192193 protected override async Task<HttpResponseMessage> SendAsync(194 HttpRequestMessage request,195 CancellationToken cancellationToken)196 {197 if (request.Headers.Authorization is null)198 {199 string[] scopes = [CopilotClient.ScopeFromSettings(_settings)];200201 IPublicClientApplication app = PublicClientApplicationBuilder202 .Create(_settings.AppClientId)203 .WithAuthority(AadAuthorityAudience.AzureAdMyOrg)204 .WithTenantId(_settings.TenantId)205 .WithRedirectUri("http://localhost")206 .Build();207208 AuthenticationResult authResponse;209 try210 {211 var account = (await app.GetAccountsAsync()).FirstOrDefault();212 authResponse = await app.AcquireTokenSilent(scopes, account).ExecuteAsync(cancellationToken);213 }214 catch (MsalUiRequiredException)215 {216 authResponse = await app.AcquireTokenInteractive(scopes).ExecuteAsync(cancellationToken);217 }218219 request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authResponse.AccessToken);220 }221222 return await base.SendAsync(request, cancellationToken);223 }224}225```226227### Console host with CopilotClient228229```csharp230using Microsoft.Agents.CopilotStudio.Client;231using Microsoft.Extensions.DependencyInjection;232using Microsoft.Extensions.Hosting;233234HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);235236var settings = new SampleConnectionSettings(237 builder.Configuration.GetSection("CopilotStudioClientSettings"));238239builder.Services.AddHttpClient("mcs").ConfigurePrimaryHttpMessageHandler(() =>240{241 return new AddTokenHandler(settings);242});243244builder.Services245 .AddSingleton(settings)246 .AddTransient<CopilotClient>(sp =>247 {248 var logger = sp.GetRequiredService<ILoggerFactory>().CreateLogger<CopilotClient>();249 return new CopilotClient(settings, sp.GetRequiredService<IHttpClientFactory>(), logger, "mcs");250 });251252IHost host = builder.Build();253var client = host.Services.GetRequiredService<CopilotClient>();254255await foreach (var activity in client.StartConversationAsync(emitStartConversationEvent: true))256{257 Console.WriteLine(activity.Type);258}259260await foreach (var activity in client.AskQuestionAsync("Hello!", null))261{262 Console.WriteLine(activity.Type);263}264```265266## Best Practices2672681. Use AgentApplication subclasses to centralize routing and error handling.2692. Use MemoryStorage only for development; use persisted storage in production.2703. Enable TokenValidation in production and require authorization on /api/messages.2714. Keep auth secrets in configuration providers (Key Vault, managed identity, env vars).2725. Reuse HttpClient from IHttpClientFactory and cache MSAL tokens.2736. Prefer async handlers and pass CancellationToken to SDK calls.274275## Reference Files276277| File | Contents |278| --- | --- |279| [references/acceptance-criteria.md](references/acceptance-criteria.md) | Import paths, hosting pipeline, Copilot Studio client patterns, anti-patterns |280281## Reference Links282283| Resource | URL |284| --- | --- |285| Microsoft 365 Agents SDK | https://learn.microsoft.com/en-us/microsoft-365/agents-sdk/ |286| AddAgent API | https://learn.microsoft.com/en-us/dotnet/api/microsoft.agents.hosting.aspnetcore.servicecollectionextensions.addagent?view=m365-agents-sdk |287| AgentApplication API | https://learn.microsoft.com/en-us/dotnet/api/microsoft.agents.builder.app.agentapplication?view=m365-agents-sdk |288| Auth configuration options | https://learn.microsoft.com/en-us/microsoft-365/agents-sdk/microsoft-authentication-library-configuration-options |289| Copilot Studio integration | https://learn.microsoft.com/en-us/microsoft-365/agents-sdk/integrate-with-mcs |290| GitHub samples | https://github.com/microsoft/agents |291
Full transparency — inspect the skill content before installing.