microsoft/teams.net

Public

mirrored from https://github.com/microsoft/teams.netAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
9dfef728feacaff7db1ea1762d5ccde4d6a434ff

Branches

Tags

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

Clone

HTTPS

Download ZIP

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

148lines · modecode

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