Skip to content

Commit 6ae4d2c

Browse files
authored
GraphResponse Support (#112)
1 parent 342997b commit 6ae4d2c

File tree

7 files changed

+280
-3
lines changed

7 files changed

+280
-3
lines changed

src/Microsoft.Graph.Core/Microsoft.Graph.Core.csproj

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@
2323
<VersionSuffix></VersionSuffix>
2424
<PackageReleaseNotes>
2525
- Adds support for TokenCredential from Azure.Core
26-
- Adds support for System.Text,Json and drops Newtonsoft.Json dependency
27-
- Fix for incorrect task cancellation #28
26+
- [Breaking Change] Adds support for System.Text,Json and drops Newtonsoft.Json dependency
27+
- [Breaking Change] Fix for incorrect task cancellation #28
28+
- Added GraphResponse object for wrapping responses
29+
- [Breaking Change] IBaseRequest now takes IResponseHandler as a member
2830
</PackageReleaseNotes>
2931
</PropertyGroup>
3032
<!--We manually configure LanguageTargets for Xamarin due to .Net SDK TFMs limitation https://github.com/dotnet/sdk/issues/491 -->

src/Microsoft.Graph.Core/Requests/BaseRequest.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,38 @@ public async Task<HttpResponseMessage> SendMultiPartRequestAsync(
213213
}
214214
}
215215

216+
/// <summary>
217+
/// Sends the request.
218+
/// </summary>
219+
/// <param name="serializableObject">The serializable object to send.</param>
220+
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the request.</param>
221+
/// <param name="completionOption">The <see cref="HttpCompletionOption"/> to pass to the <see cref="IHttpProvider"/> on send.</param>
222+
/// <returns>The <see cref="GraphResponse"/> object.</returns>
223+
public async Task<GraphResponse> SendAsyncWithGraphResponse(
224+
object serializableObject,
225+
CancellationToken cancellationToken,
226+
HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead)
227+
{
228+
var response = await this.SendRequestAsync(serializableObject, cancellationToken, completionOption).ConfigureAwait(false);
229+
return new GraphResponse(this, response);
230+
}
231+
232+
/// <summary>
233+
/// Sends the request.
234+
/// </summary>
235+
/// <param name="serializableObject">The serializable object to send.</param>
236+
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the request.</param>
237+
/// <param name="completionOption">The <see cref="HttpCompletionOption"/> to pass to the <see cref="IHttpProvider"/> on send.</param>
238+
/// <returns>The <see cref="GraphResponse"/> object.</returns>
239+
public async Task<GraphResponse<T>> SendAsyncWithGraphResponse<T>(
240+
object serializableObject,
241+
CancellationToken cancellationToken,
242+
HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead)
243+
{
244+
var response = await this.SendRequestAsync(serializableObject, cancellationToken, completionOption).ConfigureAwait(false);
245+
return new GraphResponse<T>(this, response);
246+
}
247+
216248
/// <summary>
217249
/// Sends the request.
218250
/// </summary>
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// ------------------------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information.
3+
// ------------------------------------------------------------------------------
4+
5+
namespace Microsoft.Graph
6+
{
7+
using System;
8+
using System.Net;
9+
using System.Net.Http;
10+
using System.Net.Http.Headers;
11+
/// <summary>
12+
/// The GraphResponse Object
13+
/// </summary>
14+
public class GraphResponse :IDisposable
15+
{
16+
/// <summary>
17+
/// The GraphResponse Constructor
18+
/// </summary>
19+
/// <param name="iBaseRequest">The Request made for the response</param>
20+
/// <param name="httpResponseMessage">The response</param>
21+
public GraphResponse(IBaseRequest iBaseRequest, HttpResponseMessage httpResponseMessage)
22+
{
23+
this.httpResponseMessage = httpResponseMessage;
24+
this.BaseRequest = iBaseRequest;
25+
}
26+
27+
private readonly HttpResponseMessage httpResponseMessage;
28+
29+
/// <summary>
30+
/// The Response Status code
31+
/// </summary>
32+
public HttpStatusCode StatusCode => httpResponseMessage.StatusCode;
33+
34+
/// <summary>
35+
/// The Response Content
36+
/// </summary>
37+
public HttpContent Content => httpResponseMessage.Content;
38+
39+
/// <summary>
40+
/// The Response Headers
41+
/// </summary>
42+
public HttpResponseHeaders HttpHeaders => httpResponseMessage.Headers;
43+
44+
/// <summary>
45+
/// The reference to the Request
46+
/// </summary>
47+
public IBaseRequest BaseRequest;
48+
49+
/// <summary>
50+
/// Get the native Response Message
51+
/// </summary>
52+
/// <returns></returns>
53+
public HttpResponseMessage ToHttpResponseMessage()
54+
{
55+
return httpResponseMessage;
56+
}
57+
58+
/// <summary>
59+
/// Cleanup
60+
/// </summary>
61+
public void Dispose()
62+
{
63+
httpResponseMessage?.Dispose();
64+
}
65+
}
66+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// ------------------------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information.
3+
// ------------------------------------------------------------------------------
4+
5+
namespace Microsoft.Graph
6+
{
7+
using System.Net.Http;
8+
using System.Threading.Tasks;
9+
10+
/// <summary>
11+
/// The GraphResponse Object
12+
/// </summary>
13+
public class GraphResponse<T> : GraphResponse
14+
{
15+
/// <summary>
16+
/// The GraphResponse Constructor
17+
/// </summary>
18+
/// <param name="iBaseRequest">The Request made for the response</param>
19+
/// <param name="httpResponseMessage">The response</param>
20+
public GraphResponse(IBaseRequest iBaseRequest, HttpResponseMessage httpResponseMessage)
21+
: base(iBaseRequest, httpResponseMessage)
22+
{
23+
}
24+
25+
/// <summary>
26+
/// Gets the deserialized object
27+
/// </summary>
28+
public async Task<T> GetResponseObjectAsync()
29+
{
30+
return await this.BaseRequest.ResponseHandler.HandleResponse<T>(this.ToHttpResponseMessage());
31+
}
32+
}
33+
}

src/Microsoft.Graph.Core/Requests/IBaseRequest.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ public interface IBaseRequest
4747
/// </summary>
4848
IDictionary<string, IMiddlewareOption> MiddlewareOptions { get; }
4949

50+
/// <summary>
51+
/// Gets the <see cref="IResponseHandler"/> for the request.
52+
/// </summary>
53+
IResponseHandler ResponseHandler { get; }
54+
5055
/// <summary>
5156
/// Gets the <see cref="HttpRequestMessage"/> representation of the request.
5257
/// </summary>

tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/BaseRequestTests.cs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
// ------------------------------------------------------------------------------
1+
// ------------------------------------------------------------------------------
22
// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information.
33
// ------------------------------------------------------------------------------
44

55
namespace Microsoft.Graph.DotnetCore.Core.Test.Requests
66
{
77
using Microsoft.Graph.DotnetCore.Core.Test.Mocks;
88
using Microsoft.Graph.DotnetCore.Core.Test.TestModels;
9+
using Microsoft.Graph.DotnetCore.Core.Test.TestModels.ServiceModels;
910
using Moq;
1011
using System;
1112
using System.Collections.Generic;
@@ -358,6 +359,56 @@ public async Task SendAsync_WithCustomHttpProvider()
358359
}
359360
}
360361

362+
[Fact]
363+
public async Task SendAsyncWithGraphResponse()
364+
{
365+
using (var httpResponseMessage = new HttpResponseMessage())
366+
using (TestHttpMessageHandler testHttpMessageHandler = new TestHttpMessageHandler())
367+
{
368+
string requestUrl = "https://localhost/";
369+
testHttpMessageHandler.AddResponseMapping(requestUrl, httpResponseMessage);
370+
MockCustomHttpProvider customHttpProvider = new MockCustomHttpProvider(testHttpMessageHandler);
371+
372+
BaseClient client = new BaseClient(requestUrl, authenticationProvider.Object, customHttpProvider);
373+
BaseRequest baseRequest = new BaseRequest(requestUrl, client);
374+
375+
GraphResponse returnedResponse = await baseRequest.SendAsyncWithGraphResponse("string", CancellationToken.None);
376+
377+
Assert.Equal(httpResponseMessage.StatusCode, returnedResponse.StatusCode);
378+
Assert.Equal(baseRequest, returnedResponse.BaseRequest);
379+
}
380+
}
381+
382+
[Fact]
383+
public async Task SendAsyncWithGraphResponseOfT()
384+
{
385+
using (TestHttpMessageHandler testHttpMessageHandler = new TestHttpMessageHandler())
386+
{
387+
string requestUrl = "https://localhost/";
388+
// Arrange
389+
HttpResponseMessage responseMessage = new HttpResponseMessage()
390+
{
391+
Content = new StringContent(@"{
392+
""id"": ""123"",
393+
""givenName"": ""Joe"",
394+
""surName"": ""Brown"",
395+
""@odata.type"":""test""
396+
}", Encoding.UTF8, "application/json")
397+
};
398+
testHttpMessageHandler.AddResponseMapping(requestUrl, responseMessage);
399+
MockCustomHttpProvider customHttpProvider = new MockCustomHttpProvider(testHttpMessageHandler);
400+
401+
BaseClient client = new BaseClient(requestUrl, authenticationProvider.Object, customHttpProvider);
402+
BaseRequest baseRequest = new BaseRequest(requestUrl, client);
403+
404+
GraphResponse<TestUser> returnedResponse = await baseRequest.SendAsyncWithGraphResponse<TestUser>("string", CancellationToken.None);
405+
406+
Assert.Equal(responseMessage.StatusCode, returnedResponse.StatusCode);
407+
Assert.Equal(baseRequest, returnedResponse.BaseRequest);
408+
Assert.Equal(responseMessage.Content, returnedResponse.Content);
409+
}
410+
}
411+
361412
[Fact]
362413
public void BuildQueryString_NullQueryOptions()
363414
{
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// ------------------------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information.
3+
// ------------------------------------------------------------------------------
4+
5+
6+
namespace Microsoft.Graph.DotnetCore.Core.Test.Requests
7+
{
8+
using System.Net;
9+
using System.Net.Http;
10+
using System.Text;
11+
using System.Threading.Tasks;
12+
using System.Linq;
13+
using Microsoft.Graph.DotnetCore.Core.Test.TestModels.ServiceModels;
14+
using Xunit;
15+
16+
public class GraphResponseTests : RequestTestBase
17+
{
18+
[Fact]
19+
public void GraphResponse_Initialize()
20+
{
21+
// Arrange
22+
HttpResponseMessage responseMessage = new HttpResponseMessage(HttpStatusCode.OK);
23+
BaseRequest baseRequest = new BaseRequest("http://localhost", this.baseClient) ;
24+
25+
// Act
26+
GraphResponse response = new GraphResponse(baseRequest, responseMessage);
27+
28+
// Assert
29+
Assert.Equal(responseMessage, response.ToHttpResponseMessage());
30+
Assert.Equal(responseMessage.StatusCode, response.StatusCode);
31+
Assert.Equal(baseRequest, response.BaseRequest);
32+
33+
}
34+
35+
[Fact]
36+
public void GraphResponse_ValidateHeaders()
37+
{
38+
// Arrange
39+
HttpResponseMessage responseMessage = new HttpResponseMessage(HttpStatusCode.OK);
40+
responseMessage.Headers.Add("Authorization","bearer token");// add a test header
41+
BaseRequest baseRequest = new BaseRequest("http://localhost", this.baseClient);
42+
43+
// Act
44+
GraphResponse response = new GraphResponse(baseRequest, responseMessage);
45+
46+
// Assert
47+
Assert.Equal(responseMessage, response.ToHttpResponseMessage());
48+
Assert.Equal(responseMessage.Headers.Count(), response.HttpHeaders.Count());
49+
Assert.Equal("Authorization", responseMessage.Headers.First().Key);
50+
Assert.Equal("bearer token", responseMessage.Headers.First().Value.First());
51+
52+
}
53+
54+
[Fact]
55+
public async Task ValidateResponseHandlerAsync()
56+
{
57+
// Arrange
58+
HttpResponseMessage responseMessage = new HttpResponseMessage()
59+
{
60+
Content = new StringContent(@"{
61+
""id"": ""123"",
62+
""givenName"": ""Joe"",
63+
""surName"": ""Brown"",
64+
""@odata.type"":""test""
65+
}", Encoding.UTF8, "application/json")
66+
};
67+
68+
// create a custom responseHandler
69+
IResponseHandler responseHandler = new ResponseHandler(new Serializer());
70+
BaseRequest baseRequest = new BaseRequest("http://localhost", this.baseClient)
71+
{
72+
ResponseHandler = responseHandler // use custom responseHandler
73+
};
74+
75+
76+
// Act
77+
GraphResponse<TestUser> response = new GraphResponse<TestUser>(baseRequest, responseMessage);
78+
TestUser user = await response.GetResponseObjectAsync();
79+
80+
// Assert
81+
Assert.Equal("123", user.Id);
82+
Assert.Equal("Joe", user.GivenName);
83+
Assert.Equal("Brown", user.Surname);
84+
Assert.Equal("OK", user.AdditionalData["statusCode"].ToString());
85+
86+
}
87+
}
88+
}

0 commit comments

Comments
 (0)