forked from Linq2Azure/API
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAzureRestClient.cs
155 lines (132 loc) · 6.35 KB
/
AzureRestClient.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Linq2Azure
{
/// <summary>
/// Performs REST-like options on the Azure HTTP management endpoint, taking care of authentication, error
/// handling and other functions common to all requests. This also handles optional request logging.
/// </summary>
class AzureRestClient
{
public readonly Subscription Subscription;
public readonly Uri Uri;
readonly HttpClient _httpClient;
// We use the same HttpClient for all calls to the same subscription; this allows DNS and proxy details to be
// cached across requests. Note that HttpClient allows parallel operations.
internal static HttpClient CreateHttpClient (Subscription subscription, string msVersion, Func<IEnumerable<TraceListener>> listenerFunc)
{
var handler = new WebRequestHandler();
handler.ClientCertificates.Add(subscription.ManagementCertificate);
var logger = new LoggingHandler(handler, listenerFunc);
var client = new HttpClient(logger, true);
client.DefaultRequestHeaders.Add("x-ms-version", msVersion);
return client;
}
public AzureRestClient(Subscription subscription, HttpClient httpClient, string baseUri, string servicePath)
{
Contract.Requires(subscription != null);
Contract.Requires(httpClient != null);
Subscription = subscription;
_httpClient = httpClient;
Uri = new Uri(baseUri + subscription.ID + "/" + servicePath);
}
public async Task<XElement> GetXmlAsync()
{
var response = await _httpClient.GetAsync(Uri);
return await AsXmlResponse(response);
}
public async Task<XElement> PostWithXmlResponseAsync(XElement xml)
{
var response = await SendAsync(xml, HttpMethod.Post);
return await AsXmlResponse(response);
}
public Task<HttpResponseMessage> PostAsync(XElement xml) { return SendAsync(xml, HttpMethod.Post); }
public Task<HttpResponseMessage> PostAsync() { return SendAsync(null, HttpMethod.Post); }
public Task<HttpResponseMessage> PutAsync(XElement xml) { return SendAsync(xml, HttpMethod.Put); }
async Task<HttpResponseMessage> SendAsync (XElement xml, HttpMethod method)
{
string xmlString = xml == null ? "" : xml.ToString();
var payload = new StringContent(xmlString);
payload.Headers.ContentType = new MediaTypeHeaderValue("application/xml");
HttpRequestMessage request = new HttpRequestMessage(method, Uri) { Content = payload };
var response = await _httpClient.SendAsync(request);
if ((int)response.StatusCode >= 300) await ThrowAsync(response, xmlString);
return response;
}
public async Task<HttpResponseMessage> DeleteAsync()
{
var response = await _httpClient.DeleteAsync(Uri);
if ((int)response.StatusCode >= 300) await ThrowAsync(response);
return response;
}
static async Task<XElement> AsXmlResponse(HttpResponseMessage response)
{
if ((int)response.StatusCode >= 300) await ThrowAsync(response);
var result = await response.Content.ReadAsStringAsync();
return XElement.Parse(result);
}
static async Task ThrowAsync(HttpResponseMessage response, object debugInfo = null)
{
string responseString = null;
try { responseString = await response.Content.ReadAsStringAsync(); }
catch { }
XElement errorElement = null;
if (!string.IsNullOrWhiteSpace(responseString))
errorElement = XElement.Parse(responseString);
Throw(response, errorElement, debugInfo);
}
internal static void Throw(HttpResponseMessage responseMessage, XElement errorElement, object debugInfo = null)
{
string code = null, message = null;
if (errorElement != null)
{
var ns = XmlNamespaces.WindowsAzure;
code = (string)errorElement.Elements().FirstOrDefault(e => e.Name.LocalName == "Code");
message = (string)errorElement.Elements().FirstOrDefault(e => e.Name.LocalName == "Message");
}
if (string.IsNullOrWhiteSpace(code) && string.IsNullOrWhiteSpace(message))
{
if (errorElement != null)
debugInfo = debugInfo == null
? errorElement.ToString()
: (debugInfo + "\r\n\r\n" + errorElement);
throw new AzureRestException(responseMessage, null, "Unknown error", debugInfo);
}
else
throw new AzureRestException(responseMessage, code, message, debugInfo);
}
internal class LoggingHandler : DelegatingHandler
{
Func<IEnumerable<TraceListener>> _listenerFunc;
public LoggingHandler(HttpMessageHandler nextHandler, Func<IEnumerable<TraceListener>> listenerFunc)
{
InnerHandler = nextHandler;
_listenerFunc = listenerFunc;
}
IEnumerable<TraceListener> Listeners
{
get { return _listenerFunc() ?? new TraceListener[0]; }
}
void Write(string msg) { foreach (var l in Listeners) l.Write(msg); }
void WriteLine(string msg) { foreach (var l in Listeners) l.WriteLine(msg); }
protected async override Task<HttpResponseMessage> SendAsync (HttpRequestMessage request, CancellationToken cancellationToken)
{
bool operation = request.RequestUri.AbsolutePath.Contains("/operations/");
if (!operation) Write(request.Method + ": " + request.RequestUri);
var response = await base.SendAsync(request, cancellationToken);
if (operation) Write("."); else WriteLine(" " + response.StatusCode);
return response;
}
}
}
}