Skip to content

Commit e8dc85f

Browse files
committed
Added JSON deserializable HttpResponseMessage and extensions to convert ordinary .NET HttpResponseMessage to new variant
1 parent c23cab4 commit e8dc85f

3 files changed

Lines changed: 177 additions & 0 deletions

File tree

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// MADE Apps licenses this file to you under the MIT license.
2+
// See the LICENSE file in the project root for more information.
3+
4+
namespace MADE.Networking.Extensions
5+
{
6+
using System.Net.Http;
7+
using System.Threading.Tasks;
8+
using MADE.Networking.Http.Responses;
9+
10+
/// <summary>
11+
/// Defines a collection of extensions for <see cref="HttpResponseMessage"/> objects.
12+
/// </summary>
13+
public static class HttpResponseMessageExtensions
14+
{
15+
/// <summary>
16+
/// Deserializes the content of the specified <paramref name="responseTask">response task</paramref> to a <see cref="HttpResponseMessage{T}"/>.
17+
/// </summary>
18+
/// <typeparam name="T">The type of response expected.</typeparam>
19+
/// <param name="responseTask">The task associated with the <see cref="HttpResponseMessage"/>.</param>
20+
/// <returns>A <see cref="HttpResponseMessage{T}"/> with deserialized content.</returns>
21+
public static async Task<HttpResponseMessage<T>> DeserializeAsync<T>(this Task<HttpResponseMessage> responseTask)
22+
{
23+
HttpResponseMessage response = await responseTask;
24+
return await DeserializeAsync<T>(response);
25+
}
26+
27+
/// <summary>
28+
/// Deserializes the content of the specified <paramref name="response">response</paramref> to a <see cref="HttpResponseMessage{T}"/>.
29+
/// </summary>
30+
/// <typeparam name="T">The type of response expected.</typeparam>
31+
/// <param name="response">The <see cref="HttpResponseMessage"/> to deserialize.</param>
32+
/// <returns>A <see cref="HttpResponseMessage{T}"/> with deserialized content.</returns>
33+
public static async Task<HttpResponseMessage<T>> DeserializeAsync<T>(this HttpResponseMessage response)
34+
{
35+
var deserializedResponse = new HttpResponseMessage<T>(response);
36+
await deserializedResponse.DeserializeAsync();
37+
return deserializedResponse;
38+
}
39+
}
40+
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
// MADE Apps licenses this file to you under the MIT license.
2+
// See the LICENSE file in the project root for more information.
3+
4+
namespace MADE.Networking.Http.Responses
5+
{
6+
using System;
7+
using System.Net;
8+
using System.Net.Http;
9+
using System.Net.Http.Headers;
10+
using System.Threading.Tasks;
11+
using Newtonsoft.Json;
12+
13+
/// <summary>
14+
/// Defines a HTTP response message that includes a deserializing option for the response data.
15+
/// </summary>
16+
/// <typeparam name="T">The type of response expected.</typeparam>
17+
public class HttpResponseMessage<T> : IDisposable
18+
{
19+
private HttpResponseMessage response;
20+
private bool disposed;
21+
22+
/// <summary>
23+
/// Initializes a new instance of the <see cref="HttpResponseMessage{T}"/> class with the original <see cref="HttpResponseMessage"/>.
24+
/// </summary>
25+
/// <param name="response">The original <see cref="HttpResponseMessage"/>.</param>
26+
public HttpResponseMessage(HttpResponseMessage response)
27+
{
28+
this.response = response;
29+
}
30+
31+
/// <summary>
32+
/// Gets the content of the HTTP response message.
33+
/// </summary>
34+
public HttpContent Content => this.response.Content;
35+
36+
/// <summary>
37+
/// Gets the collection of HTTP response headers.
38+
/// </summary>
39+
public HttpResponseHeaders Headers => this.response.Headers;
40+
41+
/// <summary>
42+
/// Gets a value indicating whether the HTTP response was successful.
43+
/// </summary>
44+
public bool IsSuccessStatusCode => this.response.IsSuccessStatusCode;
45+
46+
/// <summary>
47+
/// Gets the reason phrase that typically is sent by servers together with the status code.
48+
/// </summary>
49+
public string ReasonPhrase => this.response.ReasonPhrase;
50+
51+
/// <summary>
52+
/// Gets the request message which led to this response message.
53+
/// </summary>
54+
public HttpRequestMessage RequestMessage => this.response.RequestMessage;
55+
56+
/// <summary>
57+
/// Gets the status code of the HTTP response.
58+
/// </summary>
59+
public HttpStatusCode StatusCode => this.response.StatusCode;
60+
61+
/// <summary>
62+
/// Gets the HTTP message version.
63+
/// </summary>
64+
public Version Version => this.response.Version;
65+
66+
/// <summary>
67+
/// Gets the deserialized content of the original <see cref="HttpResponseMessage"/> as the specified <typeparamref name="T" /> type.
68+
/// <para>
69+
/// Note, ensure that <see cref="DeserializeAsync"/> has been called first, otherwise this value will be default.
70+
/// </para>
71+
/// </summary>
72+
public T DeserializedContent { get; private set; }
73+
74+
/// <summary>
75+
/// Allows conversion of a <see cref="HttpResponseMessage"/> to the <see cref="HttpResponseMessage{T}"/> without direct casting.
76+
/// </summary>
77+
/// <param name="response">
78+
/// The <see cref="HttpResponseMessage"/>.
79+
/// </param>
80+
/// <returns>
81+
/// The <see cref="HttpResponseMessage{T}"/>.
82+
/// </returns>
83+
public static implicit operator HttpResponseMessage<T>(HttpResponseMessage response)
84+
{
85+
return new HttpResponseMessage<T>(response);
86+
}
87+
88+
/// <summary>
89+
/// Deserializes the content of the <see cref="HttpResponseMessage"/> into the <see cref="DeserializedContent"/> value.
90+
/// </summary>
91+
/// <returns>A <see cref="Task"/> representing the result of the asynchronous operation.</returns>
92+
public async Task<T> DeserializeAsync()
93+
{
94+
this.DeserializedContent = JsonConvert.DeserializeObject<T>(await this.Content.ReadAsStringAsync());
95+
return this.DeserializedContent;
96+
}
97+
98+
/// <summary>
99+
/// Throws an exception if the <see cref="IsSuccessStatusCode"/> property for the HTTP response is false.
100+
/// </summary>
101+
/// <returns>The HTTP response message if the call is successful.</returns>
102+
public HttpResponseMessage<T> EnsureSuccessStatusCode()
103+
{
104+
this.response.EnsureSuccessStatusCode();
105+
return this;
106+
}
107+
108+
/// <summary>
109+
/// Releases the unmanaged resources and disposes of unmanaged resources used by the <see cref="HttpResponseMessage{T}"/>.
110+
/// </summary>
111+
public void Dispose()
112+
{
113+
this.Dispose(disposing: true);
114+
GC.SuppressFinalize(this);
115+
}
116+
117+
/// <summary>
118+
/// Releases the unmanaged resources used by the <see cref="HttpResponseMessage{T}"/> and optionally disposes of the managed resources.
119+
/// </summary>
120+
/// <param name="disposing">A value indicating whether to release both managed and unmanaged resources.</param>
121+
protected virtual void Dispose(bool disposing)
122+
{
123+
if (!this.disposed)
124+
{
125+
if (disposing)
126+
{
127+
this.response.Dispose();
128+
}
129+
130+
this.response = null;
131+
this.DeserializedContent = default;
132+
this.disposed = true;
133+
}
134+
}
135+
}
136+
}

src/MADE.Networking/MADE.Networking.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
This package includes networking helpers such as:
99
- NetworkRequestManager for handling an HTTP network request queue with success and error callbacks.
1010
- NetworkRequest instances for simplifying JSON GET, POST, PUT, PATCH, and DELETE requests.
11+
- HttpResponseMessage{T} for deserializing content of a HttpResponseMessage to a specified type.
1112
</Description>
1213
<PackageTags>MADE Networking Json Stream HttpClient</PackageTags>
1314
</PropertyGroup>

0 commit comments

Comments
 (0)