microsoft/teams.net

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
aamirj/StackOverflowTest

Branches

Tags

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

Clone

HTTPS

Download ZIP

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

189lines · modecode

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