Skip to content

Commit 551b189

Browse files
authored
Merge pull request #346 from microsoftgraph/dm/clientfactory
Updated to GraphClientFactory
2 parents 40bd471 + 38c08c2 commit 551b189

File tree

6 files changed

+188
-221
lines changed

6 files changed

+188
-221
lines changed

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

Lines changed: 89 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ namespace Microsoft.Graph
1111
using System.Reflection;
1212
using System.Net.Http.Headers;
1313

14-
14+
1515
/// <summary>
1616
/// GraphClientFactory class to create the HTTP client
1717
/// </summary>
18-
public static class GraphClientFactory
18+
internal static class GraphClientFactory
1919
{
2020

21-
21+
2222
/// The key for the SDK version header.
2323
private static readonly string SdkVersionHeaderName = CoreConstants.Headers.SdkVersionHeaderName;
2424

@@ -40,8 +40,13 @@ public static class GraphClientFactory
4040
private static readonly string _baseAddress = "https://graph.microsoft.com/";
4141

4242
/// Microsoft Graph service nationa cloud endpoints
43-
private static readonly Dictionary<string, string> cloudList;
44-
43+
private static readonly Dictionary<string, string> cloudList = new Dictionary<string, string>
44+
{
45+
{ Global_Cloud, "https://graph.microsoft.com" },
46+
{ USGOV_Cloud, "https://graph.microsoft.com" },
47+
{ China_Cloud, "https://microsoftgraph.chinacloudapi.cn" },
48+
{ Germany_Cloud, "https://graph.microsoft.de" }
49+
};
4550

4651
/// Global endpoint
4752
public const string Global_Cloud = "Global";
@@ -52,139 +57,93 @@ public static class GraphClientFactory
5257
/// Germany endpoint
5358
public const string Germany_Cloud = "Germany";
5459

55-
static GraphClientFactory()
56-
{
57-
cloudList = new Dictionary<string, string>();
58-
cloudList.Add(Global_Cloud, "https://graph.microsoft.com");
59-
cloudList.Add(USGOV_Cloud, "https://graph.microsoft.com");
60-
cloudList.Add(China_Cloud, "https://microsoftgraph.chinacloudapi.cn");
61-
cloudList.Add(Germany_Cloud, "https://graph.microsoft.de");
62-
}
63-
64-
65-
/// Property Version for version value
66-
public static string Version { set; get; } = "v1.0";
67-
68-
/// <summary>
69-
/// Creates a new <see cref="HttpClient"/> instance configured with the handlers provided.
70-
/// </summary>
71-
/// <param name="handlers">An ordered list of <see cref="DelegatingHandler"/> instances to be invoked as an
72-
/// <see cref="HttpRequestMessage"/> travels from the <see cref="HttpClient"/> to the network and an
73-
/// <see cref="HttpResponseMessage"/> travels from the network back to <see cref="HttpClient"/>.
74-
/// The handlers are invoked in a top-down fashion. That is, the first entry is invoked first for
75-
/// an outbound request message but last for an inbound response message.</param>
76-
/// <returns>An <see cref="HttpClient"/> instance with the configured handlers.</returns>
77-
public static HttpClient CreateClient(params DelegatingHandler[] handlers)
78-
{
79-
return Create(null, handlers);
80-
}
81-
8260
/// <summary>
83-
/// Creates a new <see cref="HttpClient"/> instance configured with the handlers provided.
61+
/// Proxy to be used with created clients
8462
/// </summary>
85-
/// <param name="innerHandler">The inner handler represents the destination of the HTTP message channel.</param>
86-
/// <param name="handlers">An ordered list of <see cref="DelegatingHandler"/> instances to be invoked as an
87-
/// <see cref="HttpRequestMessage"/> travels from the <see cref="HttpClient"/> to the network and an
88-
/// <see cref="HttpResponseMessage"/> travels from the network back to <see cref="HttpClient"/>.
89-
/// The handlers are invoked in a top-down fashion. That is, the first entry is invoked first for
90-
/// an outbound request message but last for an inbound response message.</param>
91-
/// <returns>An <see cref="HttpClient"/> instance with the configured handlers.</returns>
92-
public static HttpClient CreateClient(HttpMessageHandler innerHandler, params DelegatingHandler[] handlers)
93-
{
94-
return Create(innerHandler, handlers);
95-
}
96-
/// <summary>
97-
/// Creates a new <see cref="HttpClient"/> instance configured with the handlers provided.
98-
/// </summary>
99-
/// <param name="sovereignCloud">The <see cref="string"/>value to pass the national cloud root endpoint to client.</param>
100-
/// <param name="handlers">An ordered list of <see cref="DelegatingHandler"/> instances to be invoked as an
101-
/// <see cref="HttpRequestMessage"/> travels from the <see cref="HttpClient"/> to the network and an
102-
/// <see cref="HttpResponseMessage"/> travels from the network back to <see cref="HttpClient"/>.
103-
/// The handlers are invoked in a top-down fashion. That is, the first entry is invoked first for
104-
/// an outbound request message but last for an inbound response message.</param>
105-
/// <returns>An <see cref="HttpClient"/> instance with the configured handlers.</returns>
106-
public static HttpClient CreateClient(string sovereignCloud, params DelegatingHandler[] handlers)
107-
{
108-
if (sovereignCloud == null)
109-
{
110-
throw new ArgumentNullException(String.Format("{0} is null.", sovereignCloud, "sovereignCloud"));
111-
}
112-
string cloud = "";
113-
if (!cloudList.TryGetValue(sovereignCloud, out cloud))
114-
{
115-
throw new ArgumentException(String.Format("{0} is an unexpected national cloud.", sovereignCloud, "sovereignCloud"));
116-
}
117-
string cloudAddress = cloud + "/" + Version;
118-
Uri address = new Uri(cloudAddress);
119-
HttpClient client = Create(null, handlers);
120-
client.BaseAddress = address;
121-
return client;
122-
}
63+
public static IWebProxy Proxy { get; set; }
12364

12465
/// <summary>
125-
/// Creates a new <see cref="HttpClient"/> instance configured with the handlers, timeout, baseAddress,
126-
/// cacheControlHeaderValue and proxy provided.
66+
/// DefaultHandler is a Func that returns the HttpMessageHandler for actually making the HTTP calls.
67+
/// The default implementation returns a new instance of HttpClientHandler for each HttpClient.
12768
/// </summary>
128-
/// <param name="proxy">A <see cref="IWebProxy"/> object to be passed to client to configure InnderHandler's proxy property.</param>
129-
/// <param name="handlers">An ordered list of <see cref="DelegatingHandler"/> instances to be invoked as an
130-
/// <see cref="HttpRequestMessage"/> travels from the <see cref="HttpClient"/> to the network and an
131-
/// <see cref="HttpResponseMessage"/> travels from the network back to <see cref="HttpClient"/>.
132-
/// The handlers are invoked in a top-down fashion. That is, the first entry is invoked first for
133-
/// an outbound request message but last for an inbound response message.</param>
134-
/// <returns>An <see cref="HttpClient"/> instance with the configured handlers.</returns>
135-
public static HttpClient CreateClient(IWebProxy proxy = null, params DelegatingHandler[] handlers)
136-
{
137-
HttpClientHandler handler = new HttpClientHandler();
138-
if (proxy != null)
69+
public static Func<HttpMessageHandler> DefaultHttpHandler = () => {
70+
return new HttpClientHandler
13971
{
140-
handler.Proxy = proxy;
141-
}
142-
143-
return Create(handler, handlers);
144-
145-
}
72+
Proxy = Proxy
73+
};
74+
};
14675

14776

14877
/// <summary>
14978
/// Creates a new <see cref="HttpClient"/> instance configured with the handlers provided and with the
15079
/// provided <paramref name="innerHandler"/> as the innermost handler.
15180
/// </summary>
15281
/// <param name="innerHandler">The inner handler represents the destination of the HTTP message channel.</param>
153-
/// <param name="handlers">An ordered list of <see cref="DelegatingHandler"/> instances to be invoked as an
154-
/// <see cref="HttpRequestMessage"/> travels from the <see cref="HttpClient"/> to the network and an
82+
/// <param name="handlers">An ordered list of <see cref="DelegatingHandler"/> instances to be invoked as an
83+
/// <see cref="HttpRequestMessage"/> travels from the <see cref="HttpClient"/> to the network and an
15584
/// <see cref="HttpResponseMessage"/> travels from the network back to <see cref="HttpClient"/>.
156-
/// The handlers are invoked in a top-down fashion. That is, the first entry is invoked first for
85+
/// The handlers are invoked in a top-down fashion. That is, the first entry is invoked first for
15786
/// an outbound request message but last for an inbound response message.</param>
15887
/// <returns>An <see cref="HttpClient"/> instance with the configured handlers.</returns>
159-
private static HttpClient Create(HttpMessageHandler innerHandler, params DelegatingHandler[] handlers)
88+
public static HttpClient Create(string version = "v1.0", string nationalCloud = Global_Cloud, IEnumerable<DelegatingHandler> handlers = null)
16089
{
161-
HttpMessageHandler pipeline = CreatePipeline(innerHandler, handlers);
90+
HttpMessageHandler pipeline;
91+
if (handlers == null)
92+
{
93+
pipeline = CreatePipeline(CreateDefaultHandlers(), DefaultHttpHandler());
94+
} else
95+
{
96+
pipeline = CreatePipeline(handlers,DefaultHttpHandler());
97+
}
98+
16299
HttpClient client = new HttpClient(pipeline);
163100
client.DefaultRequestHeaders.Add(SdkVersionHeaderName, SdkVersionHeaderValue);
164101
client.Timeout = defaultTimeout;
165-
string address = _baseAddress + Version;
166-
client.BaseAddress = new Uri(address);
102+
client.BaseAddress = DetermineBaseAddress(nationalCloud, version);
167103
client.DefaultRequestHeaders.CacheControl = new CacheControlHeaderValue { NoCache = true, NoStore = true };
168104
return client;
169105
}
170106

107+
/// <summary>
108+
/// Create a default set of middleware for calling Microsoft Graph
109+
/// </summary>
110+
/// <returns></returns>
111+
public static IEnumerable<DelegatingHandler> CreateDefaultHandlers()
112+
{
113+
return new List<DelegatingHandler> {
114+
new RetryHandler(),
115+
new RedirectHandler()
116+
};
117+
}
118+
119+
private static Uri DetermineBaseAddress(string nationalCloud, string version)
120+
{
121+
string cloud = "";
122+
if (!cloudList.TryGetValue(nationalCloud, out cloud))
123+
{
124+
throw new ArgumentException(String.Format("{0} is an unexpected national cloud.", nationalCloud, "nationalCloud"));
125+
}
126+
string cloudAddress = cloud + "/" + version;
127+
return new Uri(cloudAddress);
128+
129+
}
171130

172131
/// <summary>
173132
/// Creates an instance of an <see cref="HttpMessageHandler"/> using the <see cref="DelegatingHandler"/> instances
174133
/// provided by <paramref name="handlers"/>. The resulting pipeline can be used to manually create <see cref="HttpClient"/>
175134
/// or <see cref="HttpMessageInvoker"/> instances with customized message handlers.
176135
/// </summary>
177136
/// <param name="innerHandler">The inner handler represents the destination of the HTTP message channel.</param>
178-
/// <param name="handlers">An ordered list of <see cref="DelegatingHandler"/> instances to be invoked as part
137+
/// <param name="handlers">An ordered list of <see cref="DelegatingHandler"/> instances to be invoked as part
179138
/// of sending an <see cref="HttpRequestMessage"/> and receiving an <see cref="HttpResponseMessage"/>.
180-
/// The handlers are invoked in a top-down fashion. That is, the first entry is invoked first for
139+
/// The handlers are invoked in a top-down fashion. That is, the first entry is invoked first for
181140
/// an outbound request message but last for an inbound response message.</param>
182141
/// <returns>The HTTP message channel.</returns>
183-
public static HttpMessageHandler CreatePipeline(HttpMessageHandler innerHandler, IEnumerable<DelegatingHandler> handlers)
142+
public static HttpMessageHandler CreatePipeline(IEnumerable<DelegatingHandler> handlers, HttpMessageHandler innerHandler = null )
184143
{
185144
if (innerHandler == null)
186145
{
187-
innerHandler = new HttpClientHandler();
146+
innerHandler = DefaultHttpHandler();
188147
}
189148

190149
if (handlers == null)
@@ -214,35 +173,36 @@ public static HttpMessageHandler CreatePipeline(HttpMessageHandler innerHandler,
214173
}
215174

216175

217-
/// <summary>
218-
/// Configure an instance of an <see cref="HttpClient"/>
219-
/// </summary>
220-
/// <param name="client">The <see cref="HttpClient"/> client instance need to be configured.</param>
221-
/// <param name="timeout">A <see cref="TimeSpan"/> value for the HTTP client timeout property.</param>
222-
/// <param name="baseAddress">A <see cref="Uri"/> value to set the HTTP client BaseAddress property.</param>
223-
/// <param name="cacheControlHeaderValue">A <see cref="CacheControlHeaderValue"/> value to set HTTP client DefaultRequestHeaders property.</param>
224-
/// <returns></returns>
225-
public static HttpClient Configure(HttpClient client, TimeSpan timeout, Uri baseAddress, CacheControlHeaderValue cacheControlHeaderValue)
226-
{
227-
try
228-
{
229-
client.Timeout = timeout;
230-
}
231-
catch (InvalidOperationException exception)
232-
{
233-
throw new ServiceException(
234-
new Error
235-
{
236-
Code = ErrorConstants.Codes.NotAllowed,
237-
Message = ErrorConstants.Messages.OverallTimeoutCannotBeSet,
238-
},
239-
exception);
240-
}
241176

242-
client.BaseAddress = baseAddress == null ? new Uri(_baseAddress + Version) : baseAddress;
243-
client.DefaultRequestHeaders.CacheControl = cacheControlHeaderValue ?? new CacheControlHeaderValue { NoCache = true, NoStore = true };
244-
return client;
245-
}
177+
///// <summary>
178+
///// Configure an instance of an <see cref="HttpClient"/>
179+
///// </summary>
180+
///// <param name="client">The <see cref="HttpClient"/> client instance need to be configured.</param>
181+
///// <param name="timeout">A <see cref="TimeSpan"/> value for the HTTP client timeout property.</param>
182+
///// <param name="baseAddress">A <see cref="Uri"/> value to set the HTTP client BaseAddress property.</param>
183+
///// <param name="cacheControlHeaderValue">A <see cref="CacheControlHeaderValue"/> value to set HTTP client DefaultRequestHeaders property.</param>
184+
///// <returns></returns>
185+
//public static HttpClient Configure(HttpClient client, TimeSpan timeout, Uri baseAddress, CacheControlHeaderValue cacheControlHeaderValue)
186+
//{
187+
// try
188+
// {
189+
// client.Timeout = timeout;
190+
// }
191+
// catch (InvalidOperationException exception)
192+
// {
193+
// throw new ServiceException(
194+
// new Error
195+
// {
196+
// Code = ErrorConstants.Codes.NotAllowed,
197+
// Message = ErrorConstants.Messages.OverallTimeoutCannotBeSet,
198+
// },
199+
// exception);
200+
// }
201+
202+
// client.BaseAddress = baseAddress == null ? new Uri(_baseAddress + Version) : baseAddress;
203+
// client.DefaultRequestHeaders.CacheControl = cacheControlHeaderValue ?? new CacheControlHeaderValue { NoCache = true, NoStore = true };
204+
// return client;
205+
//}
246206

247207
}
248208
}

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

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,24 @@ public HttpProvider(IAuthenticationProvider authenticationProvider, HttpMessageH
7979
new AuthenticationHandler(authenticationProvider)
8080
};
8181

82-
this.httpClient = GraphClientFactory.CreateClient(this.httpMessageHandler, handlers);
82+
GraphClientFactory.DefaultHttpHandler = () => this.httpMessageHandler;
83+
this.httpClient = GraphClientFactory.Create("v1.0", GraphClientFactory.Global_Cloud, handlers);
84+
}
85+
86+
/// <summary>
87+
/// Gets or sets the cache control header for requests;
88+
/// </summary>
89+
public CacheControlHeaderValue CacheControlHeader
90+
{
91+
get
92+
{
93+
return this.httpClient.DefaultRequestHeaders.CacheControl;
94+
}
95+
96+
set
97+
{
98+
this.httpClient.DefaultRequestHeaders.CacheControl = value;
99+
}
83100
}
84101

85102
/// <summary>

0 commit comments

Comments
 (0)