In my last few CODE Magazine articles, I've talked about mobile apps for Office 365, (Azure AD fundamentals, and Office 365 Apps for iOS using Swift). I also blogged about why I don't like the Classic SharePoint app model (Editor's note: Removed link; Sahil took his old blog down and has moved content after Dec 2016 to https://winsmarts.com/).

It's time to put all these together and offer “What's the Office 365 Developer Supposed to Do?” As always, what's written in this article are my opinions, garnered from real-world projects that I've worked on and delivered.

The SharePoint App Model

First, I realize that this topic causes a lot of feelings and indigestion. I highly encourage you to read through my blogpost, especially the comments and discussion. (Editor's note: Removed link; Sahil took his old blog down and has moved content after Dec 2016 to https://winsmarts.com/).

I have to make it very clear what I mean by the SharePoint App Model. Between the recent expansion of the definition of apps to all external code, and renaming apps to “add ins”, I should make absolutely clear that by using the term “the SharePoint App Model,” I refer to things like SharePoint hosted Apps, App Parts, AppWebProxy, AppRegNew, and Provider Hosted Apps (either S2S or OAuth). I don't include Office 365 APIs and Azure AD in the definition of the SharePoint App model.

I'm not a fan of SharePoint hosted apps. The only benefit of SharePoint hosted apps is that you don't need another server. But servers are cheap in the cloud and it's not a big deal. Even on-premises, SharePoint hosted apps are so crippled, their applicability is quite limited. By going with SharePoint hosted apps, you have the following downsides:

  • The upgrade story on AppWebs is inadequate. Preserving data across upgrades is very complicated.
  • On-premises, they can't work with FBA or any WS-Fed-based authentication.
  • They're largely unsuitable for Internet-facing WCM scenarios. In fact, the SharePoint App Model itself has numerous challenges in anonymous scenarios.
  • The App Part model is a glorified IFrame, which presents numerous challenges, such as:
    • It likes to own querystrings for extensibility, which is a very fragile way of configuring webparts.
    • Configurability is limited to what the ClientWebPart schema supports, which is not even close to the EditorPart functionality we're used to with WebParts. You can't even control the order in which the properties appear. Rich custom editors are impossible to create beyond some basic checkboxes, textboxes, dropdowns etc.
    • The IFrame lives in its own island, and requires complex workarounds to do basic things such as resizing, app part communication, deep linking, etc. Yes, I realize that some very smart people have built some amazingly impressive and ridiculously complicated workarounds to these issues. I can only describe my feelings about those “solutions” in this video.
    • Branding the AppPart presents its own set of challenges, as does the navigation. The chrome control is woefully inadequate. The way an app appears inside a site is extremely inflexible.
    • It doesn't understand well-accepted standards such as CORS, and instead implements a homegrown concoction of AppWebProxy with many limitations.
    • Many other limitations, too numerous to name. There's a reason why people don't like IFrames. Even SharePoint itself doesn't want its pages embedded as IFrames. IFrames suck! The only advantage IFrames bring is super secure isolation of the App from the surrounding page.

Provider-hosted apps are better, but aren't without their flaws either. Such as:

  • The auth mechanism between on-premises and Office 365 is different.
  • Using client-side script that interacts with SharePoint still needs and suffers from all the downsides of AppWebProxy.
  • If you're a vendor in the business of shipping a product as a provider-hosted app for on-premises, your product is pretty much nixed before it starts because of the complex installation process (as compared to a traditional WSP), and the fact that the URL of the app is hardcoded in the provider hosted app package. Yes, I realize that there are workarounds but those workarounds feel over-complicated and like mere bandages across the lack of thought in the provider-hosted app model.

Even so, provider-hosted apps offer one huge advantage. They offer the richest set of CSOM and REST APIs of any other choice. And really, nothing prevents you from wrapping provider-hosted apps into Web APIs and registering them in the same Azure AD that your Office 365 tenancy is in. For this reason, I still like provider-hosted apps, right up until Office 365 APIs offer more APIs and plug the gap for us.

Enter JavaScript

One of the biggest changes that we've seen in recent years is the advancement of JavaScript. A large percentage of development being done these days is very lightweight on the client; there are lots of Ajax calls and there's a bunch of authentication and security nonsense on the server. For the most part, C#, Swift, or JavaScript are on an almost equal footing there. Note that I said “for the most part” and “almost;” that covers 90% of the use cases you run into today. So it's not a surprise that a lot of development being done these days is being done in JavaScript.

Assuming that an Office 365 page can run JavaScript, it needs to make AJAX calls. Those calls can be broadly categorized into two parts:

  • Calls that go to Office 365 APIs or REST and CSOM where impersonation is not required. Or calls to a subset of Office 365 REST APIs that work with the current Azure AD-based authentication. In this scenario, your calls usually go to the same domain as the page itself. You can either use user authentication (plain CSOM and REST where impersonation is not required), or use OAuth for Office 365 APIs) or where impersonation is required and the currently published APIs are enough for your needs).
  • Calls that don't go to the same domain as the page. This may also include some Office 365 APIs or REST APIs, but will most certainly include WebAPIs registered in Azure AD that you author to either wrap the provider-hosted app model, or to integrate with third-party, non-Office 365 or non-SharePoint systems.

As of today, Office 365 APIs are very limited. But that's not a problem because those APIs are just WebAPIs that Microsoft wrote. And as they support more such APIs, your migration path is easy. For sure, you need to consider two things:

  • Multiple domains: where CORS fits in
  • Token-based authentication: where OAuth fits in

CORS

Cross-origin resource sharing (CORS) is a mechanism that restricts resources (e.g., fonts, JavaScript, etc.) on a webpage to be requested from another domain outside the domain from which the resource originated. GET requests are usually easy; as an example, downloading the latest AngularJS from a CDN. POST requests are a bit more complex. They're surrounded by security constraints, the called service must agree to be called from the caller URL, etc. Luckily, this is a well-established standard by now; ASP.NET supports it just like most other development platforms support it, and all modern browsers understand it very well. So CORS is something that you'll definitely be using.

OAuth

There are a lot of descriptions of what OAuth is. I've described it in my previous articles. One important thing to know about OAuth is that it's a very flexible protocol. When you request an access token, you can do so in one of many ways. You could pass a username password (grant_type=password), you could request an access token using a refresh token (grant_type=refreshtoken), or many other mechanisms.

The mechanism most suitable for a JavaScript client is the implicit grant type. It doesn't support the issuance of refresh tokens, and that's okay since JavaScript on its own has no secure way of storing the refresh token anyway.

The localStorage object is not a secure way of storing refresh tokens, even though a lot of online examples show that for simplicity.

Unlike the authorization code grant type in which the client makes separate requests for authorization and for an access token, the client receives the access token as the result of the authorization request.

Most important to note, the implicit grant type doesn't include client authentication and relies on the presence of the resource owner and the registration of the redirection URI. In the case of Azure AD, you're redirected to the AzureAD sign-on process to perform this authentication. This means that it's perfect for SPAs (JavaScript) or mobile apps that don't need to remember me, but is unsuitable for unattended scenarios, like app-only (services).

OAuth Implicit Grant and Azure AD

The good news is that Azure AD now supports implicit grant types. The bad news is, like most very newly rolled-out features in Azure AD, it's not enabled by default. You need to explicitly opt in. Here's how:

  1. Go to your application registered in AzureAD and choose “Configure.”
  2. Click on the Manage Manifest button and download the manifest file.
  3. Open the manifest file and search for the oauth2AllowImplicitFlow property. The default is false, so change it to true.
  4. Upload this manifest file back into your Web API and save it.

Applications provisioned in Azure AD aren't enabled to use the OAuth2 implicit grant by default.

Three Main Categories of Architectural Patterns

You've had lots of background and now it's time to start tackling the specifics.

There are three main architectural patterns that emerge from the above descriptions:

  • JavaScript SPA that lives on a SharePoint page and uses the Office 365 APIs that are currently available
  • JavaScript SPA that lives on a SharePoint page and uses custom Web APIs that are registered in the Azure AD
  • JavaScript SPA that lives on a SharePoint page that uses custom Web APIs that are actually provider-hosted apps.
    • These could be app only policy-based apps.
    • These could be apps that forward the user identity, which is required in scenarios such as search.

Let's tackle each one of these one by one, but before I dive into code, let me address the huge 1000lb pink elephant in the room.

What About On-Premises?

Yes, what about that big 1000lb elephant called on-premises SharePoint? The classical App Model suffered from the fact that on-premises S2S and Office 365 OAuth2 were quite different from each other. This resulted in a difference in features, approaches, and installation complexity too.

Here's the good news, if you follow the JavaScript SPA + CORS + OAuth model, everything I'm about to describe below will work on-premises also. If your on-premises customizations require you to disentangle the innards of SharePoint, I confess that farm solutions are probably still your best bet. But a lot of WSPs also involve building completely non-SharePoint functionality.

If this is the nature of your customizations, and if migration to the cloud or using better architectural patterns and newer technologies ranks high on your list, and the functionality you desire is more custom than out-of-the-box, and if it involves less SharePoint blood and guts, you should, even on-premises, go with a JavaScript + CORS + OAuth model.

But, you might say, provider-hosted apps on-premises don't support OAuth. That's right, they don't (with the exception of Hybrid OAuth implementations), but that's only if you expect SharePoint or Office 365 to be the OAuth provider.

You could write exactly the same code on premises or in Office365, as long as they target the same API signature, that you yourself author. The only difference is that in the cloud, authentication is the responsibility of Azure AD. And on-premises, the OAuth provider is written by you, as described my article here http://www.codemag.com/Article/1411031.

Not only does it simplify your Office 365 development life, it also makes code cross-compatible between Office 365 and SharePoint on premises.

This, if anything, is the biggest win in this architectural pattern. Not only does this architectural pattern simplify your Office 365 development life, it also makes code cross-compatible between Office 365 and SharePoint on premises. Now, naturally, some APIs and facilities will work only on the cloud. There's no PowerBI on-premises for instance, but as long as you interact with WebAPIs that you author, through the power of abstraction, you can offer a decent error message like “This feature is disabled on-premises” etc.

So, with all this background behind us, let's start writing some code.

JavaScript SPA Interacting with Office 365 APIs

Creating a JavaScript SPA in Office 365 is easy. I simply used SharePoint Designer to craft up an html file that acts as my front-end UI, dropped some .js files in a SharePoint folder, and used the content editor webpart to load the html file.

Before I show you the code, let's talk a little bit about the set up here.

My SPA makes an AJAX call to the Office 365 REST API, and shows me the names of all lists in my current site. In order to do so, I need to:

  1. Register my app as a native app in Office 365 Azure AD.
  2. Enable the app to allow implicit flow for authentication.
  3. Grant the app enough permissions to read the list of lists.

Registering the app is rather simple: In the Office 365 suite bar, look for the Admin button, as shown in Figure 1.

Figure 1: The various choices available in Office365
Figure 1: The various choices available in Office365

Once in the admin area, look for Azure AD, as shown in Figure 2.

Figure 2: Accessing Azure AD
Figure 2: Accessing Azure AD

Inside Azure AD, choose to add a new application with the following characteristics:

  • Choose to make it a native application.
  • Call it “ListsAngularApp”.
  • Give it a Redirect URI of https://<yourtenantname>.sharepoint.com/SitePages/DevHome.aspx, assuming that this is the page your application will finally sit on.

Once the application is registered, look for the “Add Application” green button under the “Configure” tab of your ListsAngularApp application. Choose to add the “Office 365 SharePoint Online” application. Once the application is added, choose to grant the permission shown in Figure 3.

Figure 3: Granting permissions to your application
Figure 3: Granting permissions to your application

The one last thing you need to do is enable your app to allow for the oAuth2implicitFlow described in the section above and titled “OAuth implicit Grant and Azure AD”.

The app setup is complete. Now let's write the actual app. This couldn't be any simpler; it's a simple AngularJS application, the HTML for which is shown in Listing 1.

Listing 1: HTML for my SPA

<div ng-app="adalJSApp" ng-controller="adalJSAppController">
    <div>
        <ul>
            <li ng-hide="!userInfo.isAuthenticated">Welcome {{userInfo.profile.given_name}}</li>
            <li ng-hide="!userInfo.isAuthenticated">Logout</li>
            <li ng-hide="userInfo.isAuthenticated">Login</li>
        </ul>
    </div>

    <div ng-hide="!userInfo.isAuthenticated">
        <span ng-click="getData($event);">Get data</span>
        <div ng-repeat="list in lists">
            {{$index+1}}. {{list.Title}}
        </div>
    </div>
</div>
<script src="/Assets/Scripts/angular.min.js"></script>
<script src="/Assets/Scripts/adal.js"></script>
<script src="/Assets/Scripts/app.js"></script>

As you can see, the application references three JavaScript files: the AngularJS library, the adal.js library that takes care of authentication with Azure AD, which you can grab from https://github.com/AzureAD/azure-activedirectory-library-for-js, and an app.js file that contains the custom application logic.

Examining the application further, I have some basic UI for simple login/logout functionality and displaying the user's name, and I have a “Get Data” link, clicking on which will, I'm guessing, get the names of all lists and render them in the div below.

Great! So let's look at the app.js file, as shown in Listing 2.

Listing 2: JavaScript code for my SPA

var app = angular.module('adalJSApp', ['AdalAngular']);

app.controller('adalJSAppController',
                ['$scope', '$http', 'adalAuthenticationService',
                function ($scope, $http, adalAuthenticationService) {
                    $scope.getData = function ($event) {
                        $http({
                            method: 'GET',
                            url: "https://winsmartsdev.sharepoint.com/_api/web/lists";
                        }).then(function (results) {
                            $scope.lists = results.data.value;
                        });
                        $event.stopPropagation();
                    };

                    $scope.logOut = function () { adalAuthenticationService.logOut(); }
                    $scope.LogIn = function () { adalAuthenticationService.login(); }
                }]);

app.config(['$httpProvider',
            'adalAuthenticationServiceProvider',
            function ($httpProvider, adalAuthenticationServiceProvider) {
                var endpoints = {
                    "https://winsmartsdev.sharepoint.com/";:
                        "https://winsmartsdev.sharepoint.com",
                };

                adalAuthenticationServiceProvider.init(
                    {
                        tenant: 'winsmartsdev.onmicrosoft.com',
                        clientId: '1373b921-2469-42a3-9632-af1d8aff8805',
                        endpoints: endpoints
                    }, $httpProvider);
            }]);

If you examine the app.js file, you can see that the adalAuthenticationServiceProvider is initialized with values grabbed from the ListAngularApp registration in Azure AD. Once you've done that, by simply calling login and logout methods, you can get or invalidate an access token.

And once you're logged in, you can call the getData function, which executes a simple REST API call to get the list of lists and populates the list's scope variable. This is then databound to the front-end UI.

Now, assuming that you've set up the content editor webpart to render the UI, visit your Office 365 page and you'll be greeted with a UI, as shown in Figure 4.

Figure 4: The default UI when your page loads
Figure 4: The default UI when your page loads

Go ahead and click on the Login button, and the UI should change, as shown in Figure 5.

Figure 5: The UI after you click Login
Figure 5: The UI after you click Login

Click on the Get data button and you should see the names of all lists shown in Figure 6.

Go ahead and click on the Login button, and the UI should change, as shown in Figure 5.

Figure 6: The lists on my site are securely fetched in my SPA
Figure 6: The lists on my site are securely fetched in my SPA

Congratulations, you've just written a simple Office365 application using only JavaScript. But I know what you might be thinking here: How will this work in on-premises SharePoint?

The answer is that so far this was a simple REST API. In on-premises SharePoint, you simply piggyback on user authentication to achieve the same results. Where things become really interesting is where you need to integrate with external systems, and embed custom WCF services (etc.) inside the guts of SharePoint using WSPs. Those days are over, especially since you have REST APIs, OAuth, and CORS, which is what I am going to describe next.

JavaScript SPA Interacting with Custom APIs

The real beauty of Azure AD and this JavaScript SPA model is when you start extending it using custom Web services. These custom Web services run in the setup as an ASP.NET MVC WebAPI project, also registered in Azure AD. Right off the bat, you may see that there are some new things you'll need to consider. The WebAPI project needs to somehow be registered in and authenticated by Azure AD. It definitely won't run in the same domain as Office 365. So you'll need to consider CORS. Additionally, you'll somehow have to grant access to the front-end app so that it can call the WebAPI.

Here are the major steps involved:

  1. Register the WebAPI project in Azure AD, enabling implicit flow.
  2. Author the WebAPI project, ensuring that it's authenticated using Azure AD.
  3. Run the project. I'll have to run it using SSL because Office 365 runs on SSL, and CORS calls that mix SSL with non-SSL always fail. Additionally, since I'm using just a test certificate, I'll need to add that certificate to my local trusted store so that the CORS call succeeds.
  4. And finally, make some minor changes to my JavaScript SPA, so it calls the Azure AD protected WebAPI.

Registering the WebAPI Project

This couldn't be simpler! You can do it either directly in Azure AD or via Visual Studio. Doing it directly in Azure AD is the mechanism I prefer, because I know what's going on. I hate black boxes. But registering the WebAPI in AzureAD by hand presents a chicken and egg situation. To register the WebAPI in Azure AD, I need to know the URL it will run on, which I don't know until I have created the WebAPI project, which I cannot create unless I know the registration details from Azure AD. The workaround is to use a fake URL and match up the values manually afterwards, which is what I typically do, but for the purposes of keeping this article shorter than the Encyclopedia Britannica, I'll use the simpler method and create a new ASP.NET Web Application using .NET 4.5.1. I'll call it “SampleWebAPI” choose to support WebAPI, and change the authentication to “Cloud – Single Organization,” as shown in Figure 7.

Figure 7: Creating a new WebAPI project
Figure 7: Creating a new WebAPI project

This creates a single-tenant WebAPI project and registers it for you. Make sure that you register your project in the same AzureAD as your Office 365 tenancy.

Make sure that you register your project in the same AzureAD as your Office 365 tenancy.

Once the project is created, visit your Azure AD once again, to ensure that the project appears in the list of registered applications. While you are in the newly registered “SampleWebAPI” project in Azure AD, also allow implicit flow on it, as described earlier.

Authoring the WebAPI Project

Here's your opportunity to enhance your Office 365 tenancy with whatever you wish. Out of the box, the project gives you a Values controller, which is good enough for demo purposes. But really, you could write code here to expose anything as a REST service, callable via your JavaScript SPA. You could also use roles tied to claims; you could go quite crazy here really.

Could you turn this WebAPI project into a provider-hosted app for SharePoint? Absolutely! And this is your opportunity to bring all of REST and CSOM that Microsoft hasn't yet given us official APIs for right into the Office 365 programming model. The big win is that you have one consistent way of writing code today and tomorrow.

What if this was on-premises? Then you'd just turn your WebAPI project into an OAuth provider and instead of using adal.js to get an access token, you'd get the access token using a custom authinterceptor, which I have demonstrated with full code in my previous CODE Magazine articles. The big win here is a consistent programming model between on-premises and the cloud.

Running the Project

The eventual client of this WebAPI project is going to be an AngularJS SPA running in Office 365. The call will be made under CORS. It fails because you're not using a valid SSL cert for dev purposes. So let's fix that. You don't need to spend $100 on a real cert; you'll simply trust the certificate that Visual Studio uses.

Press F5 to run your Web API project, and note that it starts up on an SSL URL. Try visiting the get values controller at https://localhost:44309/api/values (your port number will be different). You will be rudely greeted with a download, which is actually an HTTP 401.

If you open Fiddler, it looks like Figure 8.

Figure 8: The WebAPI requires authentication
Figure 8: The WebAPI requires authentication

The API tells us that it expects OAuth to succeed. But at least you know that the API is there and is successfully asking for authentication. You could get an OAuth access token manually and test things out, but let's skip that. For now, click on the padlock by the URL in the address bar. You should see the certificate details, as shown in Figure 9.

Figure 9: The localhost certificate that you need to trust
Figure 9: The localhost certificate that you need to trust

This is the certificate that you need to trust. Just a quick warning, if you see “DO_NOT_TRUST_FiddlerRoot” there, close Fiddler and hit F5. Click on the “View certificates” link and in the ensuing dialog box, as shown in Figure 10, click on the “Install Certificate” button. Then choose to install the certificate with the prompted default values.

Figure 10: Trusting the certificate
Figure 10: Trusting the certificate

Great! The WebAPI is all set. All that's left is to make a very minor change in the JavaScript SPA, and this show will be on the road.

Authoring the JavaScript SPA

Before your JavaScript SPA can call the WebAPI, you need to grant it access. Now here's the issue: the WebAPI, as it is registered right now, is registered in a “Single Tenant Mode;” in other words, only your company can call it. You can change it to be callable from your multitenant client in two ways:

  1. Make the API multitenant
  2. Keep it single-tenant and download/upload the manifest adding information that makes it callable. I described this technique in my article on Azure AD.

Instead of doing either of those things, I'm going to use a shortcut for now. Simply change the WebAPI to multi-tenant, save it, change it back to single-tenant, and then save it again. That's it! Unless you have need for custom roles, your basic ability to call the WebAPI is enabled by doing this simple trick. Maybe it's a bug in the Azure AD portal, I don't know, except it works and it saves time. And if it ever stops working, you can always go back to hand-editing the JSON manifest.

Once you have made this change, ensure that you grant the permission, as shown in Figure 11.

Figure 11: Granting permissions to your SPA
Figure 11: Granting permissions to your SPA

Next, you need to start making some code changes! First, let's focus on the JavaScript. I'm going to use the same JavaScript shown in Listing 2 and make some very minor changes.

The first change is to allow AngularJS to make a CORS call. This is done by simply adding the following to your app:

app.config(['$httpProvider',
    function($httpProvider) {
        $httpProvider.defaults.useXDomain = true;
       delete $httpProvider.defaults.headers.common['X-Requested-With'];
    }
]);

Next, change the endpoints variable to reflect the new settings.

var endpoints = {
    "https://localhost:44309/api/Values":
    "https://winsmartsdev.onmicrosoft.com/SampleWebAPI";,
};

Finally, make a change to the actual $http call; we are, after all, calling a completely different endpoint this time around.

$http({
    method: 'GET',
    url: "https://localhost:44309/api/Values"
}).then(function (results) {
    $scope.values = results.data;
});

This completes the JavaScript changes. The final JavaScript can be seen in Listing 3.

Listing 3: My CORS ready JavaScript

var app = angular.module('adalJSApp', ['AdalAngular']);

app.controller('adalJSAppController', ['$scope', '$http', 
    'adalAuthenticationService', function ($scope, $http, 
    adalAuthenticationService) {
        $scope.getData = function ($event) {
            $http({
                method: 'GET',
                url: "https://localhost:44309/api/Values"
            }).then(function (results) {
                $scope.values = results.data;
            });
            $event.stopPropagation();
        };

        $scope.logOut = function () { adalAuthenticationService.logOut(); }
        $scope.LogIn = function () { adalAuthenticationService.login(); }
    }]);

app.config(['$httpProvider', 
    'adalAuthenticationServiceProvider', function ($httpProvider, 
    adalAuthenticationServiceProvider) {
        var endpoints = {
            "https://localhost:44309/api/Values":
            "https://winsmartsdev.onmicrosoft.com/SampleWebAPI";,
        };

        adalAuthenticationServiceProvider.init(
        {
            tenant: 'winsmartsdev.onmicrosoft.com',
            clientId: '1373b921-2469-42a3-9632-af1d8aff8805',
            endpoints: endpoints
        }, $httpProvider);
    }]);

app.config(['$httpProvider', function($httpProvider) 
    {
        $httpProvider.defaults.useXDomain = true;
        delete $httpProvider.defaults.headers.common['X-Requested-With'];
    }
]);

Accordingly, you also need to change the HTML page slightly. This change is simple; you only need to change the variable that you key databinding from. Like this:

<div ng-repeat="value in values">
    {{$index+1}}. {{value}}
</div>

The client-side changes are complete. Now run your WebAPI project and the Office 365 SPA. You should see an error, as shown in Figure 12.

Figure 12: The CORS error
Figure 12: The CORS error

The reason you're getting this error is that even though your JavaScript SPA is doing what it's supposed to do, you haven't yet allowed the WebAPI itself to be callable on CORS. Fixing this is very easy. Simply install the Microsoft.Aspnet.Cors nugget package using this package manager console command:

install-package Microsoft.Aspnet.Cors

Then, in the WebAPIConfig class, in the Register method, add the following lines of code:

var corsAttr =
    new System.Web.Http.Cors.EnableCorsAttribute(
        "https://winsmartsdev.sharepoint.com", "*", "*");
config.EnableCors(corsAttr);

With this one little change, you've allowed code sitting on your Office365 page to make CORS requests to your WebAPI.

Now go ahead and run your application again and verify that you're able to call your WebAPI, as shown in Figure 13.

Figure 13: The custom WebAPI registered in the Office 365 tenancy is being called from the Office 365 page
Figure 13: The custom WebAPI registered in the Office 365 tenancy is being called from the Office 365 page

Summary

We're certainly going through interesting times. A lot of what we do is still on-premises. A lot of push that we experience is toward the cloud. Certainly there are advantages in the cloud, and even those that may seem like disadvantages lead to better and cleaner architectural patterns that can be applied to on premises.

The problem, of course, is that as an entire community, including Microsoft, we're all learning. We're learning the best way to extend Office 365, and only experience teaches us better and newer ways of doing things.

In this article, I shared how I'm tackling this problem. I shared why I don't like the classic SharePoint App model. I see no use for SharePoint hosted apps and I see limited use for provider-hosted apps. I shared why I feel that Office 365 APIs and Azure AD are the right investments. I also explained an architectural pattern that you can apply to SharePoint on-premises today, even while making your transition to the cloud painless. In fact, you may be faced with the daunting challenge of writing code that works on both on-premises and Office 365. These approaches will take you there.

Until next time, happy coding!