microsoft/teams.net

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
aacebo/mcp-client

Branches

Tags

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

Clone

HTTPS

Download ZIP

Libraries/Microsoft.Teams.Common/Http/HttpClient.cs

179lines · modecode

1using System.Net.Http.Json;
2using System.Text.Json;
3using System.Text.Json.Serialization;
4
5using Microsoft.Teams.Common.Logging;
6
7namespace Microsoft.Teams.Common.Http;
8
9public interface IHttpClient : IDisposable
10{
11 public IHttpClientOptions Options { get; }
12
13 public Task<IHttpResponse<string>> SendAsync(IHttpRequest request, CancellationToken cancellationToken = default);
14 public Task<IHttpResponse<TResponseBody>> SendAsync<TResponseBody>(IHttpRequest request, CancellationToken cancellationToken = default);
15}
16
17public class HttpClient : IHttpClient
18{
19 public IHttpClientOptions Options { get; }
20
21 protected System.Net.Http.HttpClient _client;
22 protected ILogger _logger;
23
24 public HttpClient()
25 {
26 _client = new System.Net.Http.HttpClient();
27 _logger = new ConsoleLogger().Child("Http.Client");
28 Options = new HttpClientOptions();
29 Options.Apply(_client);
30 }
31
32 public HttpClient(IHttpClientOptions options)
33 {
34 _client = new System.Net.Http.HttpClient();
35 _logger = options.Logger?.Child("Http.Client") ?? new ConsoleLogger().Child("Http.Client");
36 Options = options;
37 Options.Apply(_client);
38 }
39
40 public HttpClient(System.Net.Http.HttpClient client)
41 {
42 _client = client;
43 _logger = new ConsoleLogger().Child("Http.Client");
44 Options = new HttpClientOptions();
45 Options.Apply(_client);
46 }
47
48 public async Task<IHttpResponse<string>> SendAsync(IHttpRequest request, CancellationToken cancellationToken = default)
49 {
50 var httpRequest = CreateRequest(request);
51 var httpResponse = await _client.SendAsync(httpRequest);
52 return await CreateResponse(httpResponse, cancellationToken);
53 }
54
55 public async Task<IHttpResponse<TResponseBody>> SendAsync<TResponseBody>(IHttpRequest request, CancellationToken cancellationToken = default)
56 {
57 var httpRequest = CreateRequest(request);
58 var httpResponse = await _client.SendAsync(httpRequest, cancellationToken);
59 return await CreateResponse<TResponseBody>(httpResponse, cancellationToken);
60 }
61
62 public void Dispose()
63 {
64 _client.Dispose();
65 }
66
67 protected HttpRequestMessage CreateRequest(IHttpRequest request)
68 {
69 var httpRequest = new HttpRequestMessage(
70 request.Method,
71 request.Url
72 );
73
74 Options.Apply(httpRequest);
75
76 if (request.Body is not null)
77 {
78 if (request.Body is string stringBody)
79 {
80 httpRequest.Content = new StringContent(stringBody);
81 }
82 else if (request.Body is IEnumerable<KeyValuePair<string, string>> dictionaryBody)
83 {
84 httpRequest.Content = new FormUrlEncodedContent(dictionaryBody);
85 }
86 else
87 {
88 httpRequest.Content = JsonContent.Create(request.Body, options: new JsonSerializerOptions()
89 {
90 DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
91 });
92 }
93 }
94
95 foreach (var kv in request.Headers)
96 {
97 if (kv.Key.StartsWith("Content-"))
98 {
99 httpRequest.Content?.Headers.TryAddWithoutValidation(kv.Key, kv.Value);
100 continue;
101 }
102
103 httpRequest.Headers.TryAddWithoutValidation(kv.Key, kv.Value);
104 }
105 return httpRequest;
106 }
107
108 protected async Task<IHttpResponse<string>> CreateResponse(HttpResponseMessage response, CancellationToken cancellationToken = default)
109 {
110 if (!response.IsSuccessStatusCode)
111 {
112 var errorBody = await ParseErrorBody(response);
113
114 throw new HttpException()
115 {
116 Headers = response.Headers,
117 StatusCode = response.StatusCode,
118 Body = errorBody,
119 Request = response.RequestMessage
120 };
121 }
122
123 var body = await response.Content.ReadAsStringAsync() ?? throw new ArgumentNullException();
124
125 return new HttpResponse<string>()
126 {
127 Body = body,
128 Headers = response.Headers,
129 StatusCode = response.StatusCode
130 };
131 }
132
133 protected async Task<IHttpResponse<TResponseBody>> CreateResponse<TResponseBody>(HttpResponseMessage response, CancellationToken cancellationToken = default)
134 {
135 if (!response.IsSuccessStatusCode)
136 {
137 var errorBody = await ParseErrorBody(response);
138
139 throw new HttpException()
140 {
141 Headers = response.Headers,
142 StatusCode = response.StatusCode,
143 Body = errorBody,
144 Request = response.RequestMessage,
145 };
146 }
147
148 var body = await response.Content.ReadFromJsonAsync<TResponseBody>(cancellationToken) ?? throw new ArgumentNullException();
149
150 return new HttpResponse<TResponseBody>()
151 {
152 Body = body,
153 Headers = response.Headers,
154 StatusCode = response.StatusCode
155 };
156 }
157
158 private async Task<object> ParseErrorBody(HttpResponseMessage response)
159 {
160 var content = await response.Content.ReadAsStringAsync() ?? throw new ArgumentNullException();
161 object errorBody = content;
162
163 try
164 {
165 var bodyAsJson = JsonSerializer.Deserialize<Dictionary<string, object>>(content);
166
167 if (bodyAsJson is not null)
168 {
169 errorBody = bodyAsJson;
170 }
171 }
172 catch
173 {
174 // content is probably not a valid json
175 }
176
177 return errorBody;
178 }
179}