This is the 4th article in my Challenges in Office 365 development – and how to address them series. In the past, I’ve recommended the use of *multiple* Office 365 tenancies where custom development around Office 365/SharePoint Online is happening - after all, the need for separate dev/test/production environments typically doesn’t go away in the cloud, just because these aren’t physical environments you yourself are hosting. BUT, this multiple tenancy arrangement sometimes brings additional challenges – in previous articles I’ve discussed how dev/test Office 365 environments often don’t have production-like aspects such as identity integration and SSO, but any development of custom apps also brings challenges. Fundamentally this is because both Office 365 apps and (typically) SharePoint Add-ins need to be registered in each environment where the app will be used – and this gets problematic because each registration gives a different client secret and password, but your app typically only caters for one. But before we get too deep into the problem (and potential solutions), let’s consider this in the context of my article series:
The problem – using the Office 365 APIs when using multiple environments
So I’m focusing primarily on Office 365 apps here - in other words, some kind of application (a web or client app) which uses the Office 365 APIs. Of course, there are other flavors of apps, such as provider-hosted SharePoint Add-ins – I’ll discuss these specifically towards the end of the article, since they have some different considerations.
But Office 365 apps are becoming “the new normal” for app development in Office 365, not least because you can step outside of the Office 365 APIs and use good old-fashioned SharePoint CSOM/REST APIs if you need to (but without having to use SharePoint app authentication). So, in my view it’s starting to make less sense to create apps which will run in Office 365 as a SharePoint Add-in, rather than just creating an Office 365 app. But back to the story - to be able to read/write data to Office 365, the critical factor is that the app is registered with the Azure AD behind the Office 365 tenancy you’re using.
If you’re not ultra-familiar with this area and that sentence doesn’t make sense to you, consider that each Office 365 tenancy has an Azure subscription behind it. By default, this is a background thing only, and only contains the Azure AD directory, which holds your Office 365 users. But it can be turned into a “full” Azure subscription by providing a credit card – this unlocks the ability to use the full set of other Azure capabilities in this subscription, such as Azure web apps.
Now, if your app is a web application and you want to host it in Azure, the app itself does NOT need to be published to (and run from) from this Azure subscription. But it IS mandatory that the app is registered in this Azure AD. I’ve seen quite a few developers trip up over this – perhaps because they published the application to an Azure subscription they have access to, but this in fact has no relationship to the Azure instance (and specifically the Azure AD directory) behind Office 365.
So, we could show this relationship like this:
So, what’s the problem with our app needing to be registered in different places? Well, in addition to the general overhead which comes with this, the big issue is that each registration gives a different client ID and password. However, the design of both Office 365 apps and SharePoint Add-ins (provider-hosted) is that the client ID and password are stored in web.config – Microsoft’s authentication-handling code which gets included in every app looks for them here.
Assuming we don’t want some weird arrangement of having different web.config files for each environment, what can we do? Well, I guess some other options could be web.config transformations or rewriting Microsoft’s auth/credential-handling code – but neither of those are appealing.
If you’re hosting your app in the cloud, Azure has some nice functionality in the form of “deployment slots” which can help here.
Azure Deployment Slots – a brief introduction
Deployment Slots are a capability of Azure Web Apps (previously known as Azure Websites). They are only available when you’re using a Standard or Premium pricing plan. If you go into the “Settings” area of your web app, you can click into “Deployment Slots” and from here create a slot:
You might name this slot something like “Staging”. You can choose whether to copy any config from your existing “main” slot (which is there by default), or not:
For Office 365 apps, this isn’t important as there aren’t lots of config settings to worry about. Using this process you can create up to 5 deployment slots on a Standard plan, and up to 20 on a Premium plan – each slot effectively gives you an additional “instance” of your web application, accessible on a different URL. So for a website at http://mysite.azurewebsites.net, if you create two slots named “test” and “staging”, you’ll end up with a set of URLs like this:
This is great Azure feature, which provides test/staging capabilities for your site in a simple way. There are two key aspects which provide useful support:
- The ability to “swap” the content of deployment slots – this is effectively your deployment mechanism to promote a version of your site’s code from test/staging to production
- Each deployment slot can have its own configuration, such as connection strings and AppSettings values
For the configuration settings, values can be entered in the Azure portal (or via the Azure APIs), and when you do this these values override any specified in web.config - it’s this feature that we can leverage for Office 365 and SharePoint applications. There are a few other things to line-up so that your app can authenticate to Office 365/SharePoint, but I’ll go through those later.
In terms of working with deployment slots, you can deploy your site/app to a particular slot using the typical “publish to Azure” approaches – publish from Visual Studio, Web Deploy, PowerShell, FTP, publish from source control and so on. Once you’re at the point where your app is deployed to a staging slot, to push this version of the code to production you can swap the staging and production slots – either with this button in the Azure portal:
..or with the Switch-AzureWebsiteSlot PowerShell command. This truly is a swap, and in fact happens via a simple DNS update – so if all is good with your code update, you now have an out-of-date codebase back in your staging slot. You can fix that by simply overwriting the content there with a subsequent direct publish to that slot, but what’s useful here is that you have a quick, robust roll-back mechanism to lean on if things didn’t go to plan.
You can read Set up staging environments for web apps in Azure App Service to understand more about working with Deployment Slots in general, but I want to now discuss them specifically for Office 365 apps and SharePoint Add-ins – with the former first.
Implementing dev/test/production for Office 365/SharePoint apps using Deployment Slots
So now that we understand something of how deployment slots work, let’s consider ways in which they can be useful for Office 365 apps and SharePoint Add-ins. For one thing, the “slot-specific configuration” capability is great because we could use it to specify a different client ID and password for different environments, thus side-stepping the single web.config file problem. But interestingly, deployment slots also give us a way to have dev/test/production instances of our app, without having to register them with different Office 365/SharePoint environments. Let’s think about that for a second:
Implementing dev/test/production PURELY on the Azure side What I’m suggesting here is that deployment slots are used to implement dev/test/production PURELY on the Azure side. Using an Office 365 app as an example, all instances of the app are actually registered with the production Office 365 environment only. This is great because it allows us to avoid many of the problems we listed earlier in this series – things like dev/test environments suffering from different configuration (e.g. authentication, Office 365 plan type etc.), a reduced set of users, lower quality content/data, and so on. We get to now build and test our app in the context of production, and in particular, against the Azure AD directory that holds our production Office 365 users. However, we are still maintaining the dev/test/production separation of our app that we need to do a good job of releasing and maintaining the thing. Our app still has robust ALM practices, but they’re implemented on the Azure side – and that can work well, since that’s where the app’s code and implementation is.
There are few details to line-up, since you need a registration of your app for each “instance”, even if they all happen in one Office 365 environment. But it’s simple enough, and I’ll go through these shortly.
So, hopefully I’m demonstrating that this can be a good option. But before we go much further, it’s also worth considering things to be careful of and when it might NOT be appropriate:
But consider if your app can do "dangerous" things in testing! So, we have our dev/test/production instances of our app, and these may or may not be running the same version of the codebase (e.g. it might be different during an upgrade cycle). But all instances are talking to the same Office 365 tenancy – this is usually good because the same Azure AD is used, but it can also be bad (or at least need some consideration) depending on what your app does. If your app can read/write to Office 365 data, and presumably it can, then consider that it’s the same set of Office 365 mail, calendar items, tasks and OneDrive for Business files that all instances of your app are running against – and this is the user’s production data! Clearly if your app can WRITE data, send e-mails or make other changes, you need to bear this in mind, especially when testing. Similarly, if you’re doing anything with SharePoint Online data (e.g. writing data to lists or libraries), then the same consideration exists. You could implement some specific logic in your app, but ultimately the “separation only in Azure” approach may not be appropriate for all cases – you’ll need to use some judgement as to whether you’d be better handling ALM another way. For example, this could be registering your app in each environment you have and publishing each to a separate Azure web app.
What it looks like – using Deployment Slots for dev/test/prod in an Office 365 app
So, creating a new Deployment Slot will give you a new URL such as https://mysite-staging.azurewebsites.net, and it will now be listed in the Azure Portal:
But at this point, the slot is empty and has no website content:
So, we need to publish our app/website content to this slot – either using one of the approaches described above (such as publishing from Visual Studio), or perhaps something better. If we’re using Visual Studio Online for source control, it’s very simple to have automated builds deploy the latest build to a particular deployment slot – so your CI process always deploys to a test or staging slot, but you manually choose when to swap that with production for example. I’ll show some of this CI approach in a video in a future post - but in the end we just need to ensure our files get published to the staging slot somehow. HOWEVER, your app will NOT be fully working at this point! At first glance, however, all looks good and you should see your app is now visible at the slot’s URL (N.B. I’m using the Office 365 Starter Project for ASP.NET MVC here):
BUT, your app will not be able to authenticate to Office 365 at this time – it is not known to Azure AD. If you click the “Sign in” link and enter credentials, you’ll get an error effectively telling you that you can’t sign in – most likely saying “the reply address ‘foo’ does not match the expected reply addresses for configured for the application [app ID]”, like this:
What’s happening here is that the values in web.config for the Client ID and password are being used. The ClientID found there matches the Azure AD app registration for the production slot – but we’re on a different URL in the staging slot, hence the “reply address does not match” error. Additionally, there’s no real way of getting to the staging version of the app (except typing the URL in the address bar), because it doesn’t appear in the Office 365 My Apps page or App Launcher. So, the two things we need to do now are:
1. Manually register the staging instance of the app in Azure AD – we’ll specify the staging slot URL for the app’s Redirect URL here, and we also need to grant appropriate permissions.
2. Configure “slot-specific” override values for the Client ID and password in Azure – to do this, we obtain the Client ID and password from the staging registration in Azure AD, and then use the Azure portal (or API) to configure these against the staging slot, to override web.config.
We’ll go into these steps in more detail next, but at this point I like to create a simple icon to distinguish the staging version of the app in the My Apps page – something like this will do:
All we’re trying to do is ensure we can tell which app is which in the My Apps page later on. But let’s now go into those two steps in more detail:
Manually registering the staging instance of the app in Azure AD
If you’ve developed an app which talks to the Office 365 APIs, you might be familiar with the “Add Connected Service..” dialog in Visual Studio which enables you to register the app in Office 365 and grant permissions. Here, we need to perform the same steps that Visual Studio does but directly in Azure AD.
To register the staging app, we go into the Directory area of Azure AD (N.B. we have to use the “old” portal at the time of writing, since Azure Active Directory is not yet available in the preview portal), and in the Applications area we click the ‘Add’ button:
The next few images show the next steps in the app registration wizard – here we’re supplying some details of our app, and notably, specifying the URL of our staging slot as the sign-on URL:
Once we’re through the wizard, our staging app is registered in Azure AD:
We now need to configure it:
On the “Configure” tab, we upload our amazing logo and more importantly, obtain the client ID and password that Azure has generated for this app registration. For the key, you need to select a key duration from the dropdown and the string representing the key will be available when you click ‘Save’. At this point, copy these values and store them in a safe place – we’ll need them in the next step:
Depending on what the application actually does, we also need to grant permissions to the respective data and services in Office 365. For example, maybe it needs to read or write to Exchange Online mailboxes and calendars, or work SharePoint sites and files:
Once saved, the registration is complete and your app will appear in the My Apps page (if it is assigned to the current user):
However, if you try to sign-in at this point you’ll STILL get the sign-in error:
So, we now need to override the web.config values to match our staging app details.
Add slot-specific config for the Client ID and password (key):
Now we need to add our slot-specific config, using the details we noted down earlier. This has to be done in the *new* Azure portal of course, because deployment slots are only available there J
In the “Application settings” area, we use the same key names that web.config uses, but for the values we’re using the ones we noted down earlier:
Now save the settings, and ensure you see a success notification:
And that’s it – our staging app is now registered in Azure, and everything should now be usable. I can now sign-in to the app successfully..
..and the app’s functionality works fine. For example, it can read the files in my OneDrive For Business folder:
So there we have it. We now have different versions of our running in Azure, but all hooked up to the production Office 365 tenancy. Although I’ve presented deployment slots for use in a dev/test/production way (perhaps the most common usage), clearly you could use them in whatever way you like and use whatever ALM approaches you prefer. Along these lines, a couple of other Azure capabilities could be useful too, such as Traffic Routing.
Azure coolness - Traffic Routing for deployment slots
Traffic Routing is a feature which allows me to direct a certain percentage of traffic to my app to a particular slot. This could be useful in a few scenarios – a soft rollout of some new functionality, A/B testing and so on. Essentially I can define what proportion of traffic each slot should receive:
Traffic Routing is cookie-based, and so there are a couple of ways to override the core behavior (which doesn’t allow segregation of traffic by any particular logic) by implementing code around this, but there’s probably not a huge amount more to say about Traffic Routing. It’s certainly a feature which could be useful in some usages though, so bear it in mind. Let’s switch our attention now to other aspects of Office 365/SharePoint development, and how things work here.
SharePoint Add-ins (provider-hosted) – what’s the deal with these?
Many of the same considerations apply for SharePoint Add-ins – here, the app gets registered with AppRegNew.aspx, and the client ID/secret is then added to the SharePoint environment’s list of “known remote callers” (i.e. AppPrincipals). Clearly, if you’re using dev/test/production SharePoint environments, then the Add-in needs to be registered with each. However, there are a couple of other things to consider for this type:
- An alternative to registering with AppRegNew.aspx is to use the Seller Dashboard instead. This *isn’t* purely for app vendors selling apps through the Store – it makes a lot of sense to use it in an in-house corporate environment too, because you get to sidestep having to register with each different environment. (Back in the opening section of this article, it’s this option which made me say that SharePoint add-ins *typically* need to be registered in different environments – i.e. not always :))
- If you do use AppRegNew.aspx to register your SharePoint add-in, a notable difference compared to Office 365 apps is that you can provide the same client ID/secret across your different environments (since the fields on the AppRegNew.aspx form are textboxes which you can you type into). However, consider that even with this approach you’d still need different app packages to be deployed, since each will have a different redirect URL.
- If you’re hosting your remote components in Azure, all instances of your app could live in the same Azure subscription, with no worries about the fact that they all share the same Azure Active Directory (in contrast to Office 365 apps). This is because Azure AD isn’t used for SharePoint add-in authentication – it doesn’t come into the picture.
Summary
Azure deployment slots offer some interesting capabilities for development of Office 365 apps and SharePoint add-ins. The idea that we could implement dev/test/production versions of our app which are all talking to the same Office 365 tenancy can be very useful, as it helps get past many of the challenges with non-production Office 365 environments outlined at the beginning of this series – lack of production data, lack of a full directory of users, lack of SSO due to different authentication methods, lack of Yammer Enterprise and so on. As discussed, you need to consider if the approach outlined here is appropriate for your case. You may need to take care if your app can write data to Office 365/SharePoint for example.
But, deployment slots offer some useful possibilities around app development, and they are certainly be a useful tool in the implementer’s toolbox.