microsoft/teams.net

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v2.0.7

Branches

Tags

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

Clone

HTTPS

Download ZIP

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

192lines · modeblame

fc613a0dKavin11 months ago1// Copyright (c) Microsoft Corporation. All rights reserved.
82a4e3c3Rajan1 years ago2// Licensed under the MIT License.
3
fc613a0dKavin11 months ago4using System.Net.Http.Headers;
73e7847aAlex Acebo1 years ago5using 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{
15public IHttpClientOptions Options { get; }
16
17public Task<IHttpResponse<string>> SendAsync(IHttpRequest request, CancellationToken cancellationToken = default);
18public Task<IHttpResponse<TResponseBody>> SendAsync<TResponseBody>(IHttpRequest request, CancellationToken cancellationToken = default);
19}
20
2846e4f6Alex Acebo8 months ago21public class HttpClient : IHttpClient
73e7847aAlex Acebo1 years ago22{
23public IHttpClientOptions Options { get; }
24
25protected System.Net.Http.HttpClient _client;
26protected ILogger _logger;
27
ed542af7Rido8 months ago28private readonly JsonSerializerOptions _jsonSerializerOptions = new JsonSerializerOptions()
29{
30DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
31};
32
73e7847aAlex Acebo1 years ago33public HttpClient()
34{
35_client = new System.Net.Http.HttpClient();
36_logger = new ConsoleLogger().Child("Http.Client");
37Options = new HttpClientOptions();
38Options.Apply(_client);
39}
40
41public HttpClient(IHttpClientOptions options)
42{
43_client = new System.Net.Http.HttpClient();
44_logger = options.Logger?.Child("Http.Client") ?? new ConsoleLogger().Child("Http.Client");
45Options = options;
46Options.Apply(_client);
47}
48
49public HttpClient(System.Net.Http.HttpClient client)
50{
51_client = client;
52_logger = new ConsoleLogger().Child("Http.Client");
53Options = new HttpClientOptions();
54Options.Apply(_client);
55}
56
57public async Task<IHttpResponse<string>> SendAsync(IHttpRequest request, CancellationToken cancellationToken = default)
58{
59var httpRequest = CreateRequest(request);
60var httpResponse = await _client.SendAsync(httpRequest);
61return await CreateResponse(httpResponse, cancellationToken);
62}
63
64public async Task<IHttpResponse<TResponseBody>> SendAsync<TResponseBody>(IHttpRequest request, CancellationToken cancellationToken = default)
65{
66var httpRequest = CreateRequest(request);
67var httpResponse = await _client.SendAsync(httpRequest, cancellationToken);
68return await CreateResponse<TResponseBody>(httpResponse, cancellationToken);
69}
70
71public void Dispose()
72{
73_client.Dispose();
74}
75
76protected HttpRequestMessage CreateRequest(IHttpRequest request)
77{
78var httpRequest = new HttpRequestMessage(
79request.Method,
80request.Url
81);
82
83Options.Apply(httpRequest);
84
f3c0dad5Alex Acebo1 years ago85if (request.Body is not null)
73e7847aAlex Acebo1 years ago86{
87if (request.Body is string stringBody)
88{
89httpRequest.Content = new StringContent(stringBody);
90}
60ae88b8fallothakor1 years ago91else if (request.Body is IEnumerable<KeyValuePair<string, string>> dictionaryBody)
73e7847aAlex Acebo1 years ago92{
93httpRequest.Content = new FormUrlEncodedContent(dictionaryBody);
94}
60ae88b8fallothakor1 years ago95else
73e7847aAlex Acebo1 years ago96{
ed542af7Rido8 months ago97string body = JsonSerializer.Serialize(request.Body, _jsonSerializerOptions);
98httpRequest.Content = new StringContent(body, System.Text.Encoding.UTF8, "application/json");
60ae88b8fallothakor1 years ago99}
73e7847aAlex Acebo1 years ago100}
101
60ae88b8fallothakor1 years ago102foreach (var kv in request.Headers)
103{
fc613a0dKavin11 months ago104if (kv.Key.StartsWith("Content-") && httpRequest.Content != null)
60ae88b8fallothakor1 years ago105{
fc613a0dKavin11 months ago106if (kv.Key == "Content-Type")
107{
108httpRequest.Content.Headers.ContentType = new MediaTypeHeaderValue(kv.Value.First());
109continue;
110}
111
112httpRequest.Content.Headers.TryAddWithoutValidation(kv.Key, kv.Value);
60ae88b8fallothakor1 years ago113continue;
114}
115
116httpRequest.Headers.TryAddWithoutValidation(kv.Key, kv.Value);
117}
73e7847aAlex Acebo1 years ago118return httpRequest;
119}
120
121protected async Task<IHttpResponse<string>> CreateResponse(HttpResponseMessage response, CancellationToken cancellationToken = default)
122{
123if (!response.IsSuccessStatusCode)
124{
20d75721Kavin1 years ago125var errorBody = await ParseErrorBody(response);
73e7847aAlex Acebo1 years ago126
127throw new HttpException()
128{
129Headers = response.Headers,
130StatusCode = response.StatusCode,
20d75721Kavin1 years ago131Body = errorBody,
132Request = response.RequestMessage
73e7847aAlex Acebo1 years ago133};
134}
135
bfbe94f7Alex Acebo1 years ago136var body = await response.Content.ReadAsStringAsync() ?? throw new ArgumentNullException();
73e7847aAlex Acebo1 years ago137
138return new HttpResponse<string>()
139{
140Body = body,
141Headers = response.Headers,
142StatusCode = response.StatusCode
143};
144}
145
146protected async Task<IHttpResponse<TResponseBody>> CreateResponse<TResponseBody>(HttpResponseMessage response, CancellationToken cancellationToken = default)
147{
148if (!response.IsSuccessStatusCode)
149{
20d75721Kavin1 years ago150var errorBody = await ParseErrorBody(response);
73e7847aAlex Acebo1 years ago151
152throw new HttpException()
153{
154Headers = response.Headers,
155StatusCode = response.StatusCode,
156Body = errorBody,
157Request = response.RequestMessage,
158};
159}
160
bfbe94f7Alex Acebo1 years ago161var body = await response.Content.ReadFromJsonAsync<TResponseBody>(cancellationToken) ?? throw new ArgumentNullException();
73e7847aAlex Acebo1 years ago162
163return new HttpResponse<TResponseBody>()
164{
165Body = body,
166Headers = response.Headers,
167StatusCode = response.StatusCode
168};
169}
20d75721Kavin1 years ago170
171private async Task<object> ParseErrorBody(HttpResponseMessage response)
172{
173var content = await response.Content.ReadAsStringAsync() ?? throw new ArgumentNullException();
174object errorBody = content;
175
176try
177{
ed542af7Rido8 months ago178var bodyAsJson = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(content);
20d75721Kavin1 years ago179
180if (bodyAsJson is not null)
181{
182errorBody = bodyAsJson;
183}
184}
185catch
186{
187// content is probably not a valid json
188}
189
190return errorBody;
191}
73e7847aAlex Acebo1 years ago192}