/// <summary>
/// Executes an asynchronous request to the given resource and deserializes the response to an object of T.
/// </summary>
/// <typeparam name="T">The type to deserialize to.</typeparam>
/// <param name="restRequest">The RestRequest to execute.</param>
/// <returns>An object of T.</returns>
public async Task <T> ExecuteAsync <T>(RestRequest restRequest) where T : class
{
T result = null;
var url = restRequest.GetFormattedResource(BaseUrl);
if (string.IsNullOrWhiteSpace(restRequest.DateFormat) && !string.IsNullOrWhiteSpace(DateFormat))
{
restRequest.DateFormat = DateFormat;
}
var handler = new CompressedHttpClientHandler {
AllowAutoRedirect = true
};
_client = new HttpClient(handler);
if (!string.IsNullOrWhiteSpace(UserAgent))
{
_client.DefaultRequestHeaders.Add("user-agent", UserAgent);
}
var message = new HttpRequestMessage(restRequest.Method, new Uri(restRequest.Resource, UriKind.RelativeOrAbsolute));
foreach (var header in Headers)
{
message.Headers.Add(header.Key, header.Value);
}
if (restRequest.Method == HttpMethod.Post || restRequest.Method == HttpMethod.Put)
{
var contentString = new StringContent(restRequest.GetRequestBody(), Encoding.UTF8, restRequest.GetContentType());
message.Content = contentString;
}
HttpResponseMessage response = null;
response = await _client.SendAsync(message);
response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsStringAsync();
//TODO: Handle Error
if (response.Content.Headers.ContentType.MediaType == "application/xml")
{
// RWM: IDEA - The DataContractSerializer doesn't like attributes, but will handle everything else.
// So instead of trying to mess with a double-conversion to JSON and then to the Object, we'll just turn the attributes
// into elements, and sort the elements into alphabetical order so the DataContracterializer doesn't crap itself.
// On post, use a C# attribute to specify if a property is an XML attribute, DataContractSerialize to XML, then
// query the object for [XmlAttribute] attributes and move them from elements to attributes using code similar to below.
// If the POST request requires the attributes in a certain order, oh well. Shouldn't have used PHP :P.
XElement root = XElement.Parse(responseContent);
XElement newRoot = (XElement)Transform(restRequest.IgnoreRootElement ? root.Descendants().First() : root, restRequest);
using (var memoryStream = new MemoryStream(Encoding.Unicode.GetBytes(newRoot.ToString())))
{
var settings = new XmlReaderSettings {
IgnoreWhitespace = true
};
using (var reader = XmlReader.Create(memoryStream, settings))
{
try
{
var serializer = new DataContractSerializer(typeof(T));
result = serializer.ReadObject(reader) as T;
}
catch (SerializationException ex)
{
throw new PortableRestException(string.Format("The serializer failed on node '{0}'", reader.Name), reader.Name, ex);
}
}
}
}
else
{
result = JsonConvert.DeserializeObject <T>(responseContent);
}
return(result);
}