microsoft/teams.net

Public

mirrored fromhttps://github.com/microsoft/teams.netAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
copilot/sub-pr-338

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

core/src/Microsoft.Teams.Bot.Compat/CompatBotAdapter.cs

127lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4using System.Text.Json;
5using Microsoft.AspNetCore.Http;
6using Microsoft.Bot.Builder;
7using Microsoft.Bot.Schema;
8using Microsoft.Extensions.DependencyInjection;
9using Microsoft.Extensions.Logging;
10using Microsoft.Teams.Bot.Apps;
11using Microsoft.Teams.Bot.Core;
12using Newtonsoft.Json;
13
14
15namespace Microsoft.Teams.Bot.Compat;
16
17/// <summary>
18/// Provides a Bot Framework adapter that enables compatibility between the Bot Framework SDK and a custom bot
19/// application implementation.
20/// </summary>
21/// <remarks>Use this adapter to bridge Bot Framework turn contexts and activities with a custom bot application.
22/// This class is intended for scenarios where integration with non-standard bot runtimes or legacy systems is
23/// required.</remarks>
24/// <param name="sp">The service provider used to resolve dependencies.</param>
25public class CompatBotAdapter(IServiceProvider sp) : BotAdapter
26{
27 private readonly JsonSerializerOptions _writeIndentedJsonOptions = new() { WriteIndented = true };
28 private readonly TeamsBotApplication botApplication = sp.GetRequiredService<TeamsBotApplication>();
29 private readonly IHttpContextAccessor? httpContextAccessor = sp.GetService<IHttpContextAccessor>();
30 private readonly ILogger<CompatBotAdapter>? logger = sp.GetService<ILogger<CompatBotAdapter>>();
31
32 /// <summary>
33 /// Deletes an activity from the conversation.
34 /// </summary>
35 /// <param name="turnContext">The turn context containing the activity information. Cannot be null.</param>
36 /// <param name="reference">The conversation reference identifying the activity to delete.</param>
37 /// <param name="cancellationToken">A cancellation token that can be used to cancel the asynchronous operation.</param>
38 /// <returns>A task that represents the asynchronous delete operation.</returns>
39 public override async Task DeleteActivityAsync(ITurnContext turnContext, ConversationReference reference, CancellationToken cancellationToken)
40 {
41 ArgumentNullException.ThrowIfNull(turnContext);
42 await botApplication.ConversationClient.DeleteActivityAsync(turnContext.Activity.FromCompatActivity(), cancellationToken: cancellationToken).ConfigureAwait(false);
43 }
44
45 /// <summary>
46 /// Sends a set of activities to the conversation.
47 /// </summary>
48 /// <param name="turnContext">The turn context for the conversation. Cannot be null.</param>
49 /// <param name="activities">An array of activities to send. Cannot be null.</param>
50 /// <param name="cancellationToken">A cancellation token that can be used to cancel the asynchronous operation.</param>
51 /// <returns>
52 /// A task that represents the asynchronous operation. The task result contains an array of <see cref="ResourceResponse"/>
53 /// objects with the IDs of the sent activities.
54 /// </returns>
55 public override async Task<ResourceResponse[]> SendActivitiesAsync(ITurnContext turnContext, Activity[] activities, CancellationToken cancellationToken)
56 {
57 ArgumentNullException.ThrowIfNull(activities);
58 ArgumentNullException.ThrowIfNull(turnContext);
59
60 ResourceResponse[] responses = new Microsoft.Bot.Schema.ResourceResponse[activities.Length];
61
62 for (int i = 0; i < activities.Length; i++)
63 {
64 Activity activity = activities[i];
65
66 if (activity.Type == ActivityTypes.Trace)
67 {
68 return [new ResourceResponse() { Id = null }];
69 }
70
71 if (activity.Type == "invokeResponse")
72 {
73 WriteInvokeResponseToHttpResponse(activity.Value as InvokeResponse);
74 return [new ResourceResponse() { Id = null }];
75 }
76
77 SendActivityResponse? resp = await botApplication.SendActivityAsync(activity.FromCompatActivity(), cancellationToken).ConfigureAwait(false);
78
79 logger?.LogInformation("Resp from SendActivitiesAsync: {RespId}", resp?.Id);
80
81 responses[i] = new Microsoft.Bot.Schema.ResourceResponse() { Id = resp?.Id };
82 }
83 return responses;
84 }
85
86 /// <summary>
87 /// Updates an existing activity in the conversation.
88 /// </summary>
89 /// <param name="turnContext">The turn context for the conversation.</param>
90 /// <param name="activity">The activity with updated content. Cannot be null.</param>
91 /// <param name="cancellationToken">A cancellation token that can be used to cancel the asynchronous operation.</param>
92 /// <returns>
93 /// A task that represents the asynchronous operation. The task result contains a <see cref="ResourceResponse"/>
94 /// with the ID of the updated activity.
95 /// </returns>
96 public override async Task<ResourceResponse> UpdateActivityAsync(ITurnContext turnContext, Activity activity, CancellationToken cancellationToken)
97 {
98 ArgumentNullException.ThrowIfNull(activity);
99 UpdateActivityResponse res = await botApplication.ConversationClient.UpdateActivityAsync(
100 activity.Conversation.Id,
101 activity.Id,
102 activity.FromCompatActivity(),
103 cancellationToken: cancellationToken).ConfigureAwait(false);
104 return new ResourceResponse() { Id = res.Id };
105 }
106
107 private void WriteInvokeResponseToHttpResponse(InvokeResponse? invokeResponse)
108 {
109 ArgumentNullException.ThrowIfNull(invokeResponse);
110 HttpResponse? response = httpContextAccessor?.HttpContext?.Response;
111 if (response is not null && !response.HasStarted)
112 {
113 response.StatusCode = invokeResponse.Status;
114 using StreamWriter httpResponseStreamWriter = new(response.BodyWriter.AsStream());
115 using JsonTextWriter httpResponseJsonWriter = new(httpResponseStreamWriter);
116 logger?.LogTrace("Sending Invoke Response: \n {InvokeResponse} with status: {Status} \n", System.Text.Json.JsonSerializer.Serialize(invokeResponse.Body, _writeIndentedJsonOptions), invokeResponse.Status);
117 if (invokeResponse.Body is not null)
118 {
119 Microsoft.Bot.Builder.Integration.AspNet.Core.HttpHelper.BotMessageSerializer.Serialize(httpResponseJsonWriter, invokeResponse.Body);
120 }
121 }
122 else
123 {
124 logger?.LogWarning("HTTP response is null or has started. Cannot write invoke response. ResponseStarted: {ResponseStarted}", response?.HasStarted);
125 }
126 }
127}
128