1

Using VS 2017 Community. Azure.

I have Azure setup, I have a blank webapp created just for test purpose.

My actual site is an Angular2 MVC5 site, currently run locally.

The following is the code that should... Contact azure providing secret key(the site is registered in azure Active directory). From this i get a token i then can use to contact azure api and get list of sites.

WARNING: code is all Sausage code/prototype.

Controller

public ActionResult Index()
{
    try
        {
            MainAsync().ConfigureAwait(false);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.GetBaseException().Message);
        }

        return View();
}

static async System.Threading.Tasks.Task MainAsync()
    {
        string tenantId = ConfigurationManager.AppSettings["AzureTenantId"];
        string clientId = ConfigurationManager.AppSettings["AzureClientId"];
        string clientSecret = ConfigurationManager.AppSettings["AzureClientSecret"];

        string token = await AuthenticationHelpers.AcquireTokenBySPN(tenantId, clientId, clientSecret).ConfigureAwait(false);

        using (var client = new HttpClient())
        {
            client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
            client.BaseAddress = new Uri("https://management.azure.com/");

            await MakeARMRequests(client);
        }
    }

static async System.Threading.Tasks.Task MakeARMRequests(HttpClient client)
    {
        const string ResourceGroup = "ProtoTSresGrp1";

        // Create the resource group

        // List the Web Apps and their host names

        using (var response = await client.GetAsync(
            $"/subscriptions/{Subscription}/resourceGroups/{ResourceGroup}/providers/Microsoft.Web/sites?api-version=2015-08-01"))
        {
            response.EnsureSuccessStatusCode();

            var json = await response.Content.ReadAsAsync<dynamic>().ConfigureAwait(false);
            foreach (var app in json.value)
            {
                Console.WriteLine(app.name);
                foreach (var hostname in app.properties.enabledHostNames)
                {
                    Console.WriteLine("  " + hostname);
                }
            }
        }
    }

Controller class uses a static helper class that gets the token from Azure...

public static class AuthenticationHelpers
{
    const string ARMResource = "https://management.core.windows.net/";
    const string TokenEndpoint = "https://login.windows.net/{0}/oauth2/token";
    const string SPNPayload = "resource={0}&client_id={1}&grant_type=client_credentials&client_secret={2}";

    public static async Task<string> AcquireTokenBySPN(string tenantId, string clientId, string clientSecret)
    {
        var payload = String.Format(SPNPayload,
                                    WebUtility.UrlEncode(ARMResource),
                                    WebUtility.UrlEncode(clientId),
                                    WebUtility.UrlEncode(clientSecret));

        var body = await HttpPost(tenantId, payload).ConfigureAwait(false);
        return body.access_token;
    }

    static async Task<dynamic> HttpPost(string tenantId, string payload)
    {
        using (var client = new HttpClient())
        {
            var address = String.Format(TokenEndpoint, tenantId);
            var content = new StringContent(payload, Encoding.UTF8, "application/x-www-form-urlencoded");
            using (var response = await client.PostAsync(address, content).ConfigureAwait(false))
            {
                if (!response.IsSuccessStatusCode)
                {
                    Console.WriteLine("Status:  {0}", response.StatusCode);
                    Console.WriteLine("Content: {0}", await response.Content.ReadAsStringAsync());
                }

                response.EnsureSuccessStatusCode();

                return await response.Content.ReadAsAsync<dynamic>().ConfigureAwait(false);
            }
        }

    }
}

ISSUE: Ok so the issue I was faced with was Async Deadlocks in my code. So i looked at this stack post stack post here

I fixed the issues by putting in .ConfigureAwait(false) on most of the await declarations.

Code runs and gets all the way back to the controller with a token etc and runs through the MakeARMRequests(HttpClient client) method, however the json only returns 1 result "{[]}" when i debug and as such ignores the loops.

My question is, is my code the culprit here? or would this point to a configuration setting in azure?

Community
  • 1
  • 1
lemunk
  • 2,616
  • 12
  • 57
  • 87
  • `however the json only returns 1 result "{[]}" when i debug...` <= does it return something different when you do not debug? – Igor Mar 22 '17 at 11:04

2 Answers2

1

Not sure if this is the issue you are facing now BUT you never wait for a result from your async action in the first method Index in your code. MainAsync().ConfigureAwait(false); will immediately return and continue to the next block while the task MainAsync() will start in the background. The catch handler also does nothing because you dont wait f or a result.

Option 1 (recommended)

public async Task<ActionResult> Index()
{
    try
    {
        await MainAsync().ConfigureAwait(false);
    }
    catch (Exception e)
    {
        Console.WriteLine(e.GetBaseException().Message);
    }

    return View();
}

Option 2 if you can't use async/await for some reason

public ActionResult Index()
{
    try
    {
        MainAsync().GetAwaiter().GetResult();
    }
    catch (Exception e)
    {
        Console.WriteLine(e.GetBaseException().Message);
    }

    return View();
}
Igor
  • 60,821
  • 10
  • 100
  • 175
  • Thanks for catching that, Although not the answer it is an issue in the future that may have been overlooked. upvoted – lemunk Mar 22 '17 at 11:38
0

The Code looks OK and runs fine, Anyone who could help verify would be good, but one can assume this is OK. The issue for this was configuration in azure, When you register an app you must set a certain number of Access controls via the subscription.

In this case I set some more specific things for the web api , for now set the app as owner and made reference to service management api.

Probably don't need half the "IAM" added in the subscription to the registered app, I simply went through adding the relevant ones and debugging each time until finally i got the results expected.

lemunk
  • 2,616
  • 12
  • 57
  • 87