Using an Azure PublishSettings File From C#

Monday, April 28, 2014

One of the fantastic aspects of cloud computing in general is the capability to automate every step of a process. Hanselman and Brady Gaster have both written about the Windows Azure Management Libraries, see Penny Pinching in the Cloud and Brady’s Announcement for some details.

The management libraries are wrappers around the Azure HTTP API and are a boon for businesses that run products on Azure. Not only do the libraries allow for automation but they also allow you (or rather me, at this very minute) to create custom applications for a business to manage Azure services. Although the Azure portal is full of features, it can be overwhelming to someone who doesn’t work with Azure on a daily basis. An even bigger issue is how there is no concept of roles in the portal. If you want to give someone the ability to shutdown a VM from the portal, you also give them the ability to do anything in the portal, including the ability to accidently delete all services the business holds dear.

A custom portal solves both of the above problems because you can build something tailored to the services and vocabulary the business uses, as well as perform role checks and restrict dangerous activities. The custom portal will need a management certificate to perform activities against the Azure API, and the easiest approach to obtain a management certificate is to download  a publish setting file.

Once you have a publish settings file, you can write some code to parse the information inside and make the data available to higher layer management activities. There are a few libraries out there that can work with publish setting files, but I have some special requirements and want to work with them directly. The contents of a publish settings file look like the following (and note there can be multiple Subscription elements inside).

<PublishData>
  <PublishProfile
    SchemaVersion="2.0"
    PublishMethod="AzureServiceManagementAPI">
    <Subscription
      ServiceManagementUrl="https://management.core.windows.net"
      Id="...guid..."
      Name="Happy Subscription Name"
      ManagementCertificate="...base64 encoded certificate data..." />
  </PublishProfile>
</PublishData>

 

Let’s use the following code as an example goal for how my custom publish settings should work. I want to:

  1. Create an object representing the settings by just handing off some text.
  2. Loop through the subscription in a file
  3. Ask each subscription to create credentials I can use to invoke the Azure HTTP API.
var fileContents = File.ReadAllText("odetocode.publishsettings");
var publishSettingsFile = new PublishSettingsFile(fileContents);

foreach (var subscription in publishSettingsFile.Subscriptions)
{
    Console.WriteLine("Showing compute services for: {0}", subscription.Name);
    
    var credentials = subscription.GetCredentials();
    using (var client = new ComputeManagementClient(credentials, subscription.ServiceUrl))
    {
        var services = client.HostedServices.List();
        foreach (var service in services)
        {
            Console.WriteLine("\t{0}", service.ServiceName);
        }
    }
}

It is the PublishSettingsFile class that parses the XML and creates PublishSetting objects. I’ve removed some error handling from the class so it doesn’t appear too intimidating.

public class PublishSettingsFile
{
    public PublishSettingsFile(string fileContents)
    {
        var document = XDocument.Parse(fileContents);

        _subscriptions = document.Descendants("Subscription")
                            .Select(ToPublishSettings).ToList();
    }

    private PublishSettings ToPublishSettings(XElement element)
    {
        var settings = new PublishSettings();
        settings.Id = Get(element, "Id");
        settings.Name = Get(element, "Name");
        settings.ServiceUrl = GetUri(element, "ServiceManagementUrl");
        settings.Certificate = GetCertificate(element, "ManagementCertificate");
        return settings;
    }        

    private string Get(XElement element, string name)
    {
        return (string) element.Attribute(name);
    }

    private Uri GetUri(XElement element, string name)
    {
        return new Uri(Get(element, name));
    }

    private X509Certificate2 GetCertificate(XElement element, string name)
    {
        var encodedData = Get(element, name);
        var certificateAsBytes = Convert.FromBase64String(encodedData);
        return new X509Certificate2(certificateAsBytes);
    }

    public IEnumerable<PublishSettings> Subscriptions
    {
        get
        {
            return _subscriptions;
        }
    }

    private readonly IList<PublishSettings> _subscriptions;
}

The PublishSettings class itself is relatively simple. It mostly holds data, but can also create the credentials object needed to communicate with Azure.

public class PublishSettings
{
    public string Id { get; set; }
    public string Name { get; set; }
    public Uri ServiceUrl  { get; set; }
    public X509Certificate2 Certificate { get; set; }

    public SubscriptionCloudCredentials GetCredentials()
    {
        return new CertificateCloudCredentials(Id, Certificate);
    }

}

In the future I’ll try to write more about the custom portal I’m building with ASP.NET MVC, WebAPI, and AngularJS. It has some interesting capabilities.


Comments
gravatar Mike Schellenberger Friday, May 2, 2014
Great article, I look forward to the followups. We don't like the 'god' rights everyone gets and really don't like the new portal MS is working on either.
gravatar Michael Seirer Tuesday, May 6, 2014
heya, thanks for the great article. I have one question though: when i export the publish settings file, it looks a bit different: (?xml version="1.0" encoding="utf-8"?) (PublishData) (PublishProfile PublishMethod="AzureServiceManagementAPI" Url="https://management.core.windows.net" ManagementCertificate="(cert-data)") (Subscription Id="id" Name="Abonnement-Name" /) (/PublishProfile) (/PublishData) do you have any idea why this happens? thanks Michael
gravatar Scott Tuesday, May 6, 2014
@Michael: I've never seen the ManagementCertificate element appear outside of Subscription, so I'm not sure. Backwards compatibility, maybe?
Comments are now closed.
by K. Scott Allen K.Scott Allen
My Pluralsight Courses
The Podcast!