microsoft/teams.net
Publicmirrored from https://github.com/microsoft/teams.netAvailable
core/src/Microsoft.Teams.Apps/Api/Clients/ApiClient.cs
164lines · modecode
| 1 | // Copyright (c) Microsoft Corporation. |
| 2 | // Licensed under the MIT License. |
| 3 | |
| 4 | using Microsoft.Extensions.DependencyInjection; |
| 5 | using Microsoft.Extensions.Logging; |
| 6 | using Microsoft.Teams.Core.Http; |
| 7 | |
| 8 | using CoreConversationClient = Microsoft.Teams.Core.ConversationClient; |
| 9 | using CoreUserTokenClient = Microsoft.Teams.Core.UserTokenClient; |
| 10 | |
| 11 | namespace Microsoft.Teams.Apps.Api.Clients; |
| 12 | |
| 13 | /// <summary> |
| 14 | /// Top-level API client that provides access to all Teams Bot API sub-clients. |
| 15 | /// </summary> |
| 16 | /// <remarks> |
| 17 | /// <para> |
| 18 | /// This client can be constructed in two ways: |
| 19 | /// </para> |
| 20 | /// <list type="bullet"> |
| 21 | /// <item><b>DI-friendly (no serviceUrl)</b> — Use <see cref="ApiClient(HttpClient, CoreConversationClient, CoreUserTokenClient, ILogger)"/> |
| 22 | /// and call <see cref="ForServiceUrl"/> per-request to create a scoped instance.</item> |
| 23 | /// <item><b>Fully initialized</b> — Use <see cref="ApiClient(Uri, HttpClient, CoreConversationClient, CoreUserTokenClient, ILogger)"/> |
| 24 | /// when the service URL is known upfront.</item> |
| 25 | /// </list> |
| 26 | /// </remarks> |
| 27 | public class ApiClient |
| 28 | { |
| 29 | private readonly BotHttpClient _http; |
| 30 | |
| 31 | internal CoreConversationClient ConversationClient { get; } |
| 32 | |
| 33 | internal CoreUserTokenClient UserTokenClient { get; } |
| 34 | |
| 35 | /// <summary> |
| 36 | /// The service URL used by this client. |
| 37 | /// Null when constructed without a service URL (DI-friendly constructor). |
| 38 | /// Call <see cref="ForServiceUrl"/> to create a scoped instance with a service URL. |
| 39 | /// </summary> |
| 40 | public virtual Uri ServiceUrl { get; } |
| 41 | |
| 42 | /// <summary> |
| 43 | /// Client for bot-level operations (token, sign-in). |
| 44 | /// </summary> |
| 45 | public virtual BotClient Bots { get; } |
| 46 | |
| 47 | /// <summary> |
| 48 | /// Client for conversation operations (activities, members, reactions). |
| 49 | /// </summary> |
| 50 | public virtual ConversationApiClient Conversations { get; } |
| 51 | |
| 52 | /// <summary> |
| 53 | /// Client for user-level operations (token). |
| 54 | /// </summary> |
| 55 | public virtual UserClient Users { get; } |
| 56 | |
| 57 | /// <summary> |
| 58 | /// Client for team operations. |
| 59 | /// </summary> |
| 60 | public virtual TeamClient Teams { get; } |
| 61 | |
| 62 | /// <summary> |
| 63 | /// Client for meeting operations. |
| 64 | /// </summary> |
| 65 | public virtual MeetingClient Meetings { get; } |
| 66 | |
| 67 | /// <summary> |
| 68 | /// Creates a new <see cref="ApiClient"/> without a service URL (DI-friendly). |
| 69 | /// Use <see cref="ForServiceUrl"/> to create a scoped instance bound to a specific service URL. |
| 70 | /// </summary> |
| 71 | /// <param name="httpClient">An <see cref="HttpClient"/> configured with authentication (e.g., via DI with <c>BotAuthenticationHandler</c>).</param> |
| 72 | /// <param name="conversationClient">The core conversation client for conversation/activity/member operations.</param> |
| 73 | /// <param name="userTokenClient">The core user token client for sign-in and token operations.</param> |
| 74 | /// <param name="logger">Optional logger.</param> |
| 75 | [ActivatorUtilitiesConstructor] |
| 76 | public ApiClient(HttpClient httpClient, CoreConversationClient conversationClient, CoreUserTokenClient userTokenClient, ILogger? logger = null) |
| 77 | { |
| 78 | ArgumentNullException.ThrowIfNull(httpClient); |
| 79 | ArgumentNullException.ThrowIfNull(conversationClient); |
| 80 | ArgumentNullException.ThrowIfNull(userTokenClient); |
| 81 | |
| 82 | _http = new BotHttpClient(httpClient, logger); |
| 83 | ConversationClient = conversationClient; |
| 84 | UserTokenClient = userTokenClient; |
| 85 | Bots = new BotClient(userTokenClient); |
| 86 | Users = new UserClient(userTokenClient); |
| 87 | |
| 88 | // ServiceUrl-dependent sub-clients require ForServiceUrl() before use |
| 89 | ServiceUrl = null!; |
| 90 | Conversations = null!; |
| 91 | Teams = null!; |
| 92 | Meetings = null!; |
| 93 | } |
| 94 | |
| 95 | /// <summary> |
| 96 | /// Creates a new <see cref="ApiClient"/> bound to a specific service URL. |
| 97 | /// </summary> |
| 98 | /// <param name="serviceUrl">The Bot Framework service URL.</param> |
| 99 | /// <param name="httpClient">An <see cref="HttpClient"/> configured with authentication (e.g., via DI with <c>BotAuthenticationHandler</c>).</param> |
| 100 | /// <param name="conversationClient">The core conversation client for conversation/activity/member operations.</param> |
| 101 | /// <param name="userTokenClient">The core user token client for sign-in and token operations.</param> |
| 102 | /// <param name="logger">Optional logger.</param> |
| 103 | internal ApiClient(Uri serviceUrl, HttpClient httpClient, CoreConversationClient conversationClient, CoreUserTokenClient userTokenClient, ILogger? logger = null) |
| 104 | { |
| 105 | ArgumentNullException.ThrowIfNull(serviceUrl); |
| 106 | ArgumentNullException.ThrowIfNull(httpClient); |
| 107 | ArgumentNullException.ThrowIfNull(conversationClient); |
| 108 | ArgumentNullException.ThrowIfNull(userTokenClient); |
| 109 | |
| 110 | _http = new BotHttpClient(httpClient, logger); |
| 111 | ConversationClient = conversationClient; |
| 112 | UserTokenClient = userTokenClient; |
| 113 | ServiceUrl = serviceUrl; |
| 114 | Bots = new BotClient(userTokenClient); |
| 115 | Conversations = new ConversationApiClient(serviceUrl, conversationClient); |
| 116 | Users = new UserClient(userTokenClient); |
| 117 | Teams = new TeamClient(serviceUrl.ToString(), _http); |
| 118 | Meetings = new MeetingClient(serviceUrl.ToString(), _http); |
| 119 | } |
| 120 | |
| 121 | /// <summary> |
| 122 | /// Creates a copy of an existing <see cref="ApiClient"/> with the same configuration. |
| 123 | /// </summary> |
| 124 | internal ApiClient(ApiClient client) |
| 125 | { |
| 126 | ArgumentNullException.ThrowIfNull(client); |
| 127 | |
| 128 | ServiceUrl = client.ServiceUrl; |
| 129 | _http = client._http; |
| 130 | ConversationClient = client.ConversationClient; |
| 131 | UserTokenClient = client.UserTokenClient; |
| 132 | Bots = client.Bots; |
| 133 | Conversations = client.Conversations; |
| 134 | Users = client.Users; |
| 135 | Teams = client.Teams; |
| 136 | Meetings = client.Meetings; |
| 137 | } |
| 138 | |
| 139 | // Private constructor for ForServiceUrl — shares BotHttpClient, ConversationClient, and UserTokenClient |
| 140 | private ApiClient(BotHttpClient http, CoreConversationClient conversationClient, CoreUserTokenClient userTokenClient, Uri serviceUrl) |
| 141 | { |
| 142 | _http = http; |
| 143 | ConversationClient = conversationClient; |
| 144 | UserTokenClient = userTokenClient; |
| 145 | ServiceUrl = serviceUrl; |
| 146 | Bots = new BotClient(userTokenClient); |
| 147 | Conversations = new ConversationApiClient(serviceUrl, conversationClient); |
| 148 | Users = new UserClient(userTokenClient); |
| 149 | Teams = new TeamClient(serviceUrl.ToString(), http); |
| 150 | Meetings = new MeetingClient(serviceUrl.ToString(), http); |
| 151 | } |
| 152 | |
| 153 | /// <summary> |
| 154 | /// Creates a new <see cref="ApiClient"/> scoped to the specified service URL, |
| 155 | /// sharing the underlying HTTP client and authentication. |
| 156 | /// </summary> |
| 157 | /// <param name="serviceUrl">The Bot Framework service URL for this scope.</param> |
| 158 | /// <returns>A new <see cref="ApiClient"/> bound to the given service URL.</returns> |
| 159 | public virtual ApiClient ForServiceUrl(Uri serviceUrl) |
| 160 | { |
| 161 | ArgumentNullException.ThrowIfNull(serviceUrl); |
| 162 | return new ApiClient(_http, ConversationClient, UserTokenClient, serviceUrl); |
| 163 | } |
| 164 | } |
| 165 | |