microsoft/teams.net

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
copilot/move-activity-classes-to-core-again

Branches

Tags

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

Clone

HTTPS

Download ZIP

core/src/Microsoft.Bot.Core/BotApplication.cs

147lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4using Microsoft.AspNetCore.Http;
5using Microsoft.Bot.Core.Schema;
6using Microsoft.Extensions.Configuration;
7using Microsoft.Extensions.Logging;
8
9namespace Microsoft.Bot.Core;
10
11/// <summary>
12/// Represents a bot application.
13/// </summary>
14[System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1848:Use the LoggerMessage delegates", Justification = "<Pending>")]
15public class BotApplication
16{
17 private readonly ILogger<BotApplication> _logger;
18 private readonly ConversationClient? _conversationClient;
19 private readonly string _serviceKey;
20 internal TurnMiddleware MiddleWare { get; }
21
22 /// <summary>
23 /// Initializes a new instance of the BotApplication class with the specified conversation client, configuration,
24 /// logger, and optional service key.
25 /// </summary>
26 /// <remarks>This constructor sets up the bot application and starts the bot listener using the provided
27 /// configuration and service key. The service key is used to locate authentication credentials in the
28 /// configuration.</remarks>
29 /// <param name="conversationClient">The client used to manage and interact with conversations for the bot.</param>
30 /// <param name="config">The application configuration settings used to retrieve environment variables and service credentials.</param>
31 /// <param name="logger">The logger used to record operational and diagnostic information for the bot application.</param>
32 /// <param name="sectionName">The configuration key identifying the authentication service. Defaults to "AzureAd" if not specified.</param>
33 public BotApplication(ConversationClient conversationClient, IConfiguration config, ILogger<BotApplication> logger, string sectionName = "AzureAd")
34 {
35 ArgumentNullException.ThrowIfNull(config);
36 _logger = logger;
37 _serviceKey = sectionName;
38 MiddleWare = new TurnMiddleware();
39 _conversationClient = conversationClient;
40 string appId = config["MicrosoftAppId"] ?? config["CLIENT_ID"] ?? config[$"{sectionName}:ClientId"] ?? "Unknown AppID";
41 logger.LogInformation("Started bot listener on {Port} for AppID:{AppId} with SDK version {SdkVersion}", config?["ASPNETCORE_URLS"], appId, Version);
42 }
43
44
45 /// <summary>
46 /// Gets the client used to manage and interact with conversations.
47 /// </summary>
48 /// <remarks>Accessing this property before the client is initialized will result in an exception. Ensure
49 /// that the client is properly configured before use.</remarks>
50 public ConversationClient ConversationClient => _conversationClient ?? throw new InvalidOperationException("ConversationClient not initialized");
51
52 /// <summary>
53 /// Gets or sets the delegate that is invoked to handle an incoming activity asynchronously.
54 /// </summary>
55 /// <remarks>Assign a delegate to process activities as they are received. The delegate should accept an
56 /// <see cref="CoreActivity"/> and a <see cref="CancellationToken"/>, and return a <see cref="Task"/> representing the
57 /// asynchronous operation. If <see langword="null"/>, incoming activities will not be handled.</remarks>
58 public Func<CoreActivity, CancellationToken, Task>? OnActivity { get; set; }
59
60 /// <summary>
61 /// Processes an incoming HTTP request containing a bot activity.
62 /// </summary>
63 /// <param name="httpContext"></param>
64 /// <param name="cancellationToken"></param>
65 /// <returns></returns>
66 /// <exception cref="InvalidOperationException"></exception>
67 /// <exception cref="BotHandlerException"></exception>
68 public async Task<CoreActivity> ProcessAsync(HttpContext httpContext, CancellationToken cancellationToken = default)
69 {
70 ArgumentNullException.ThrowIfNull(httpContext);
71 ArgumentNullException.ThrowIfNull(_conversationClient);
72
73 _logger.LogDebug("Start processing HTTP request for activity");
74
75 CoreActivity activity = await CoreActivity.FromJsonStreamAsync(httpContext.Request.Body, cancellationToken).ConfigureAwait(false) ?? throw new InvalidOperationException("Invalid Activity");
76
77 _logger.LogInformation("Processing activity: {Id} {Type}", activity.Id, activity.Type);
78
79 if (_logger.IsEnabled(LogLevel.Trace))
80 {
81 _logger.LogTrace("Received activity: {Activity}", activity.ToJson());
82 }
83
84 using (_logger.BeginScope("Processing activity {Type} {Id}", activity.Type, activity.Id))
85 {
86 try
87 {
88 await MiddleWare.RunPipelineAsync(this, activity, this.OnActivity, 0, cancellationToken).ConfigureAwait(false);
89 }
90 catch (Exception ex)
91 {
92 _logger.LogError(ex, "Error processing activity {Type} {Id}", activity.Type, activity.Id);
93 throw new BotHandlerException("Error processing activity", ex, activity);
94 }
95 finally
96 {
97 _logger.LogInformation("Finished processing activity {Type} {Id}", activity.Type, activity.Id);
98 }
99 return activity;
100 }
101 }
102
103 /// <summary>
104 /// Adds the specified turn middleware to the middleware pipeline.
105 /// </summary>
106 /// <param name="middleware">The middleware component to add to the pipeline. Cannot be null.</param>
107 /// <returns>An ITurnMiddleWare instance representing the updated middleware pipeline.</returns>
108 public ITurnMiddleWare Use(ITurnMiddleWare middleware)
109 {
110 MiddleWare.Use(middleware);
111 return MiddleWare;
112 }
113
114 /// <summary>
115 /// Sends the specified activity to the conversation asynchronously.
116 /// </summary>
117 /// <param name="activity">The activity to send to the conversation. Cannot be null.</param>
118 /// <param name="cancellationToken">A cancellation token that can be used to cancel the send operation.</param>
119 /// <returns>A task that represents the asynchronous operation. The task result contains the identifier of the sent activity.</returns>
120 /// <exception cref="Exception">Thrown if the conversation client has not been initialized.</exception>
121 public async Task<ResourceResponse?> SendActivityAsync(CoreActivity activity, CancellationToken cancellationToken = default)
122 {
123 ArgumentNullException.ThrowIfNull(activity);
124 ArgumentNullException.ThrowIfNull(_conversationClient, "ConversationClient not initialized");
125
126 return await _conversationClient.SendActivityAsync(activity, cancellationToken).ConfigureAwait(false);
127 }
128
129 /// <summary>
130 /// Sends a typing activity to the conversation asynchronously.
131 /// </summary>
132 /// <param name="activity">The activity containing conversation information.</param>
133 /// <param name="cancellationToken"></param>
134 /// <returns></returns>
135 public async Task<ResourceResponse?> SendTypingActivityAsync(CoreActivity activity, CancellationToken cancellationToken = default)
136 {
137 ArgumentNullException.ThrowIfNull(activity);
138 var typing = activity.CreateReplyMessageActivity();
139 typing.Type = ActivityTypes.Typing;
140 return await SendActivityAsync(typing, cancellationToken).ConfigureAwait(false);
141 }
142
143 /// <summary>
144 /// Gets the version of the SDK.
145 /// </summary>
146 public static string Version => ThisAssembly.NuGetPackageVersion;
147}
148