Renaming ARMClient to ARMLib, changing auth behavior, adding ConfigureLogin and Query

This commit is contained in:
Ahmed ElSayed 2015-01-29 18:20:49 -08:00
Родитель 7056b04214
Коммит 7182c14beb
4 изменённых файлов: 236 добавлений и 219 удалений

Просмотреть файл

@ -15,7 +15,7 @@ namespace ARMClient.Library.Runner
private static async Task Run()
{
var armClient = ARMClient.GetDynamicClient(apiVersion: "2014-04-01", authHelper: new AuthHelper(AzureEnvironments.Prod));
var armClient = ARMLib.GetDynamicClient(apiVersion: "2014-11-01").ConfigureLogin(LoginType.Upn, "userName", "password");
var resrouceGroups = await armClient.Subscriptions["{subscriptionId}"]
.ResourceGroups
@ -31,7 +31,6 @@ namespace ARMClient.Library.Runner
if (sites.Length == 0)
{
Console.WriteLine("ResrouceGroup: {0} Doesn't contain any websites!", resrouceGroup.name);
}
}
}

Просмотреть файл

@ -48,7 +48,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ARMClient.cs" />
<Compile Include="ARMLib.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>

Просмотреть файл

@ -1,216 +0,0 @@
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using ARMClient.Authentication;
using ARMClient.Authentication.AADAuthentication;
using ARMClient.Authentication.Contracts;
using Microsoft.CSharp.RuntimeBinder;
namespace ARMClient.Library
{
public class ARMClient : DynamicObject
{
private string _url = null;
private string _authorizationHeader;
private readonly string _apiVersion;
private readonly IAuthHelper _authHelper;
private readonly AzureEnvironments _azureEnvironment;
public static dynamic GetDynamicClient(string apiVersion, IAuthHelper authHelper = null,
AzureEnvironments azureEnvironment = AzureEnvironments.Prod, string url = null)
{
return new ARMClient(apiVersion, authHelper, azureEnvironment, url);
}
private ARMClient(string apiVersion, IAuthHelper authHelper = null,
AzureEnvironments azureEnvironment = AzureEnvironments.Prod, string url = null)
{
this._apiVersion = apiVersion;
this._authHelper = authHelper ?? new AuthHelper(azureEnvironment);
this._azureEnvironment = azureEnvironment;
this._url = url ?? Constants.CSMUrls[(int)azureEnvironment];
}
private ARMClient(string apiVersion, string authorizationHeader, string url)
{
this._authorizationHeader = authorizationHeader;
this._url = url;
}
public async Task InitializeToken(string subscriptionId = null)
{
if (string.IsNullOrEmpty(subscriptionId))
{
var match = Regex.Match(_url, ".*\\/subscriptions\\/(.*?)\\/", RegexOptions.IgnoreCase);
subscriptionId = match.Success ? match.Groups[1].ToString() : string.Empty;
}
if (!this._authHelper.IsCacheValid())
{
await this._authHelper.AcquireTokens().ConfigureAwait(false);
}
TokenCacheInfo cacheInfo = await this._authHelper.GetToken(subscriptionId, Constants.CSMResource).ConfigureAwait(false);
this._authorizationHeader = cacheInfo.CreateAuthorizationHeader();
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
return TryHandleDynamicCall(binder.Name, out result);
}
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
{
return TryHandleDynamicCall(indexes[0].ToString(), out result);
}
private bool TryHandleDynamicCall(string name, out object result)
{
var url = string.Format("{0}/{1}", _url, name);
result = string.IsNullOrEmpty(this._authorizationHeader)
? new ARMClient(this._apiVersion, this._authHelper, this._azureEnvironment, url)
: new ARMClient(this._apiVersion, this._authorizationHeader, url);
return true;
}
public T Get<T>()
{
return Task.Run(() => GetAsync<T>()).Result;
}
public async Task<T> GetAsync<T>()
{
var httpResponse = await InvokeAsyncDynamicMember("Get", Enumerable.Empty<object>().ToArray());
return await httpResponse.Content.ReadAsAsync<T>();
}
public T Post<T>(params object[] args)
{
return Task.Run(() => PostAsync<T>(args)).Result;
}
public async Task<T> PostAsync<T>(params object[] args)
{
var httpResponse = await InvokeAsyncDynamicMember("Post", args);
return await httpResponse.Content.ReadAsAsync<T>();
}
public T Put<T>(params object[] args)
{
return Task.Run(() => PutAsync<T>(args)).Result;
}
public async Task<T> PutAsync<T>(params object[] args)
{
var httpResponse = await InvokeAsyncDynamicMember("Put", args);
return await httpResponse.Content.ReadAsAsync<T>();
}
public T Delete<T>()
{
return Task.Run(() => DeleteAsync<T>()).Result;
}
public async Task<T> DeleteAsync<T>()
{
var httpResponse = await InvokeAsyncDynamicMember("Delete", Enumerable.Empty<object>().ToArray());
return await httpResponse.Content.ReadAsAsync<T>();
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
result = InvokeDynamicMember(binder.Name, args);
return true;
}
private object InvokeDynamicMember(string memberName, object[] args)
{
if (string.IsNullOrEmpty(this._authorizationHeader))
{
InitializeToken().Wait();
}
var isAsync = memberName.EndsWith("async", StringComparison.OrdinalIgnoreCase);
memberName = isAsync
? memberName.Substring(0, memberName.IndexOf("async", StringComparison.OrdinalIgnoreCase))
: memberName;
object result = HttpInvoke(memberName, args);
return isAsync ? result : Task.Run(() => (Task<HttpResponseMessage>)result).Result;
}
private async Task<HttpResponseMessage> InvokeAsyncDynamicMember(string memberName, object[] args)
{
if (string.IsNullOrEmpty(_authorizationHeader))
{
await InitializeToken();
}
if ((String.Equals(memberName, "get", StringComparison.OrdinalIgnoreCase)
|| String.Equals(memberName, "delete", StringComparison.OrdinalIgnoreCase)
|| String.Equals(memberName, "put", StringComparison.OrdinalIgnoreCase)
|| String.Equals(memberName, "post", StringComparison.OrdinalIgnoreCase)))
{
return await HttpInvoke(memberName, args);
}
else
{
throw new RuntimeBinderException(string.Format("'ARMClient' does not contain a http definition for '{0}'", memberName));
}
}
private Task<HttpResponseMessage> HttpInvoke(string httpVerb, object[] args)
{
var uri = string.Format("{0}?api-version={1}", this._url, this._apiVersion);
return HttpInvoke(new Uri(uri), httpVerb, args.Length > 0 ? args[0].ToString() : string.Empty);
}
private async Task<HttpResponseMessage> HttpInvoke(Uri uri, string verb, string payload)
{
using (var client = new HttpClient(new HttpClientHandler()))
{
client.DefaultRequestHeaders.Add("Authorization", this._authorizationHeader);
client.DefaultRequestHeaders.Add("User-Agent", Constants.UserAgent.Value);
client.DefaultRequestHeaders.Add("Accept", Constants.JsonContentType);
client.DefaultRequestHeaders.Add("x-ms-request-id", Guid.NewGuid().ToString());
HttpResponseMessage response = null;
if (String.Equals(verb, "get", StringComparison.OrdinalIgnoreCase))
{
response = await client.GetAsync(uri).ConfigureAwait(false);
}
else if (String.Equals(verb, "delete", StringComparison.OrdinalIgnoreCase))
{
response = await client.DeleteAsync(uri).ConfigureAwait(false);
}
else if (String.Equals(verb, "post", StringComparison.OrdinalIgnoreCase))
{
response = await client.PostAsync(uri, new StringContent(payload ?? String.Empty, Encoding.UTF8, Constants.JsonContentType)).ConfigureAwait(false);
}
else if (String.Equals(verb, "put", StringComparison.OrdinalIgnoreCase))
{
response = await client.PutAsync(uri, new StringContent(payload ?? String.Empty, Encoding.UTF8, Constants.JsonContentType)).ConfigureAwait(false);
}
else
{
throw new InvalidOperationException(String.Format("Invalid http verb '{0}'!", verb));
}
return response;
}
}
}
}

234
ARMClient.Library/ARMLib.cs Normal file
Просмотреть файл

@ -0,0 +1,234 @@
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using ARMClient.Authentication;
using ARMClient.Authentication.AADAuthentication;
using ARMClient.Authentication.Contracts;
using Microsoft.CSharp.RuntimeBinder;
using Newtonsoft.Json;
using System.Diagnostics;
namespace ARMClient.Library
{
public class ARMLib : DynamicObject
{
private string _url = null;
private TokenCacheInfo _tokenCacheInfo;
private readonly string _apiVersion;
private readonly IAuthHelper _authHelper;
private readonly AzureEnvironments _azureEnvironment;
private LoginType _loginType;
private string _tenantId;
private string _appId;
private string _appKey;
private string _userName;
private string _password;
private string _query;
public static dynamic GetDynamicClient(string apiVersion, AzureEnvironments azureEnvironment = AzureEnvironments.Prod, string url = null)
{
return new ARMLib(apiVersion, azureEnvironment, url);
}
private ARMLib(string apiVersion, AzureEnvironments azureEnvironment, string url)
{
this._apiVersion = apiVersion;
this._authHelper = new AuthHelper(azureEnvironment);
this._azureEnvironment = azureEnvironment;
this._url = url ?? Constants.CSMUrls[(int)azureEnvironment];
this._query = string.Empty;
}
private ARMLib(ARMLib oldClient, string url, string query)
{
this._loginType = oldClient._loginType;
this._apiVersion = oldClient._apiVersion;
this._appId = oldClient._appId;
this._appKey = oldClient._appKey;
this._authHelper = oldClient._authHelper;
this._tokenCacheInfo = oldClient._tokenCacheInfo;
this._azureEnvironment = oldClient._azureEnvironment;
this._loginType = oldClient._loginType;
this._password = oldClient._password;
this._tenantId = oldClient._tenantId;
this._userName = oldClient._userName;
this._query = query;
this._url = url;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
return TryHandleDynamicCall(binder.Name.FirstLetterToLowerCase(), out result);
}
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
{
return TryHandleDynamicCall(indexes[0].ToString(), out result);
}
private bool TryHandleDynamicCall(string name, out object result)
{
var url = string.Format("{0}/{1}", _url, name);
result = new ARMLib(this, url, this._query);
return true;
}
public async Task<T> GetAsync<T>()
{
var httpResponse = await HttpInvoke("Get", Enumerable.Empty<object>().ToArray()).ConfigureAwait(false);
httpResponse.EnsureSuccessStatusCode();
return await httpResponse.Content.ReadAsAsync<T>().ConfigureAwait(false);
}
public async Task<T> PostAsync<T>(params object[] args)
{
var httpResponse = await HttpInvoke("Post", args).ConfigureAwait(false);
httpResponse.EnsureSuccessStatusCode();
return await httpResponse.Content.ReadAsAsync<T>().ConfigureAwait(false);
}
public async Task<T> PutAsync<T>(params object[] args)
{
var httpResponse = await HttpInvoke("Put", args).ConfigureAwait(false);
httpResponse.EnsureSuccessStatusCode();
return await httpResponse.Content.ReadAsAsync<T>().ConfigureAwait(false);
}
public async Task<T> DeleteAsync<T>()
{
var httpResponse = await HttpInvoke("Delete", Enumerable.Empty<object>().ToArray()).ConfigureAwait(false);
httpResponse.EnsureSuccessStatusCode();
return await httpResponse.Content.ReadAsAsync<T>().ConfigureAwait(false);
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
if (binder.Name.Equals("ConfigureLogin", StringComparison.OrdinalIgnoreCase))
{
this._loginType = (LoginType) args[0];
switch (this._loginType)
{
case LoginType.Spn:
this._tenantId = args[1].ToString();
this._appId = args[2].ToString();
this._appKey = args[3].ToString();
break;
case LoginType.Upn:
this._userName = args[1].ToString();
this._password = args[2].ToString();
break;
}
result = this;
}
else if (binder.Name.Equals("Query", StringComparison.OrdinalIgnoreCase))
{
var query = this._query + "&" + args[0];
result = new ARMLib(this, this._url, query);
}
else
{
result = InvokeDynamicMember(binder.Name, args);
}
return true;
}
private object InvokeDynamicMember(string memberName, object[] args)
{
var isAsync = memberName.EndsWith("async", StringComparison.OrdinalIgnoreCase);
memberName = isAsync
? memberName.Substring(0, memberName.IndexOf("async", StringComparison.OrdinalIgnoreCase))
: memberName;
return HttpInvoke(memberName, args);
}
private Task<HttpResponseMessage> HttpInvoke(string httpVerb, object[] args)
{
var uri = string.Format("{0}?api-version={1}{2}", this._url, this._apiVersion, this._query);
return HttpInvoke(new Uri(uri), httpVerb, args.Length > 0 ? args[0] : string.Empty);
}
private async Task<HttpResponseMessage> HttpInvoke(Uri uri, string verb, object objectPayload)
{
var payload = JsonConvert.SerializeObject(objectPayload);
using (var client = new HttpClient(new HttpClientHandler()))
{
client.DefaultRequestHeaders.Add("Authorization", await GetAuthorizationHeader());
client.DefaultRequestHeaders.Add("User-Agent", Constants.UserAgent.Value);
client.DefaultRequestHeaders.Add("Accept", Constants.JsonContentType);
client.DefaultRequestHeaders.Add("x-ms-request-id", Guid.NewGuid().ToString());
HttpResponseMessage response = null;
if (String.Equals(verb, "get", StringComparison.OrdinalIgnoreCase))
{
response = await client.GetAsync(uri).ConfigureAwait(false);
}
else if (String.Equals(verb, "delete", StringComparison.OrdinalIgnoreCase))
{
response = await client.DeleteAsync(uri).ConfigureAwait(false);
}
else if (String.Equals(verb, "post", StringComparison.OrdinalIgnoreCase))
{
response = await client.PostAsync(uri, new StringContent(payload ?? String.Empty, Encoding.UTF8, Constants.JsonContentType)).ConfigureAwait(false);
}
else if (String.Equals(verb, "put", StringComparison.OrdinalIgnoreCase))
{
response = await client.PutAsync(uri, new StringContent(payload ?? String.Empty, Encoding.UTF8, Constants.JsonContentType)).ConfigureAwait(false);
}
else
{
throw new InvalidOperationException(String.Format("Invalid http verb '{0}'!", verb));
}
return response;
}
}
private async Task<string> GetAuthorizationHeader()
{
var match = Regex.Match(_url, ".*\\/subscriptions\\/(.*?)\\/", RegexOptions.IgnoreCase);
var subscriptionId = match.Success ? match.Groups[1].ToString() : null;
if (this._tokenCacheInfo == null || this._tokenCacheInfo.ExpiresOn <= DateTimeOffset.UtcNow)
{
switch (this._loginType)
{
case LoginType.Interactive:
await this._authHelper.AcquireTokens().ConfigureAwait(false);
break;
case LoginType.Spn:
await this._authHelper.GetTokenBySpn(this._tenantId, this._appId, this._appKey).ConfigureAwait(false);
break;
case LoginType.Upn:
await this._authHelper.GetTokenByUpn(this._userName, this._password).ConfigureAwait(false);
break;
}
this._tokenCacheInfo = await this._authHelper.GetToken(subscriptionId, Constants.CSMResource).ConfigureAwait(false);
}
return this._tokenCacheInfo.CreateAuthorizationHeader();
}
}
internal static class StringExtension
{
public static string FirstLetterToLowerCase(this string value)
{
return Char.ToLowerInvariant(value[0]) + value.Substring(1);
}
}
public enum LoginType
{
Upn,
Spn,
Interactive
}
}