Office Dev, Technical

File Upload to SharePoint Online

One of my peers, Doug Perkes, wrote an awesome sample project on GitHub called Office 365 SharePoint File Management which demonstrates a multi-tenant MVC application connecting to Office 365 to allow a user to upload a file to SharePoint Online. Very handy, indeed. This post gives you steps to follow to integrate the same functionality into an existing MVC application. In order to get to the point where your application can upload a file to SharePoint Online, you must first provide the ability for the user to authenticate into their Office 365 tenant and have your application configured as a multi-tenant app, which is handled by Azure Active Directory. Ignoring a bunch of plumbing code which you’ll see by following the steps below, you can then call into SharePoint Online using either the REST or CSOM API (Doug’s sample shows both.)

As you’re walking through these steps, have Doug’s repo open (or clone it locally) as you’ll be grabbing files from it. For every step where you bring a file over from the repo, update the namespace to match your project namespace.

  1. Add an Office 365 Connected Service, if not already done. To do this, you will need an Office 365 developer account which can be obtained either through your MSDN subscription or a free one-year subscription. Doug walks through how to do this in Step 3 on his GitHub repo so I won’t duplicate that here.
  2. Install EntityFramework, if not already done. Right-click -> Manage NuGet Packages, or using the Package Manager Console window.
  3. Install Microsoft.SharePointOnline.CSOM NuGet package.
  4. Add a Utils folder at the root of your project
  5. From the repo, bring in Utils/SettingsHelper.cs
  6. Add Models/ApplicationDbContext.cs
  7. Add Models/ADALTokenCache.cs
  8. Add Models/ADALTokenCacheInitializer.cs
  9. Update your Global.asax.cs
    1. Add using statement for System.Data.Entity
    2. Add the following line to the Application_Start method:
      Database.SetInitializer(new Models.ADALTokenCacheInitializer());
  10. Update your App_Start/Startup.Auth.cs file to incorporate the code from his Startup.Auth.cs
  11. Add Models/SearchResult.cs
  12. Add Models/SearchModel.cs
  13. Add Views/Home/Sites.cshtml
  14. Add ExecuteSearchQuery method from his HomeController.cs to your controller and resolve references
  15. Add Sites method from his HomeController.cs to your controller and resolve references
  16. Add ConsentApp and RefreshSession methods from his AccountController.cs to your AccountController and resolve references

Stopping here, when you run your app you will now be able to log into an Office 365 tenant and display the Sites view which will show all SharePoint sites the user has access to (you’ll need to add an entry point to the Sites view on your own, something like: @Html.ActionLink(“Start Here »”, “Sites”, “Home”, new { @class = “btn btn-primary btn-lg” }) .) This is done using the Search REST API. Doug continues in his sample to include additional views for Libraries, Upload and UploadFile which all show how to read from SPO and then upload a file to a library in SPO using CSOM. I won’t walk through the steps of how to incorporate that functionality into your project as it’s pretty repetitive for what was done above to get Sites working.

If you’d like a deeper understanding of what the code is doing, check out the two references below:

Multi-tenant MVC app using AAD to Call O365 API
Searching a SPO site using REST

Office Dev, Technical

Check Users Browser within Office 365 Add-In

When writing an Office 365 Add-In intended to be run in Office 365 (as opposed to just an Office thick client, such as Word), you may need to be concerned about which browser your user is in. I’ll cover a specific scenario and another more general scenario and how to perform the check.

Internet Explorer 9 Support

As of the writing of this post, any Add-In published to the Office Store will be validated against IE 9 and rejected if it doesn’t work. Other than random IE 9 JavaScript quirks, your Add-In may be using an Office API feature that isn’t supported in IE 9 such as the coercion type HTML when using setSelectedDataAsync. The validation team realizes there aren’t always work-arounds for these limitations and they allow us to state the Add-In doesn’t support IE 9 in the app description and “fail gracefully” with a kind error message. To check for IE 9 in your Add-In, add the following function to your app.js file within app.initialize:

// App doesn’t support IE 9
app.isBrowserSupported =
 function () {
   var ua = navigator.userAgent, tem,
   M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
   M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, ‘-?’];
   if ((tem = ua.match(/version\/(\d+)/i)) != null) M.splice(1, 1, tem[1]);
var browser = M.join(‘ ‘);
   return browser != ‘MSIE 9’;
};

Now wherever it makes sense in your Add-In to check the browser and display a kind message back to the user (perhaps in Home.js, after app.initialize() is called), add a check and behave accordingly:

if (app.isBrowserSupported()) {
   // All is good, proceed as normal
}
else {
   // Browser not supported, display kind error message and disable functionality
}

General Browser Check

For any other need to check the browser, here’s that same function but a bit more generic so you can modify to fit your needs. I “stole” this from a co-worker so I’m not sure who the original author is. If you do, please leave a comment so I can give them credit.

var ua = navigator.userAgent, tem,
M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
if (/trident/i.test(M[1])) {
    tem =
 /\brv[ :]+(\d+)/g.exec(ua) || [];
    app.showNotification(
 ‘IE ‘ + (tem[1] || ”));
}
if (M[1] === ‘Chrome’) {
    tem = ua.match(/\b(OPR|Edge)\/(\d+)/);
    if (tem !=
 null) return tem.slice(1).join(‘ ‘).replace(‘OPR’, ‘Opera’);
}
M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, ‘-?’];
if ((tem = ua.match(/version\/(\d+)/i)) != null) M.splice(1, 1, tem[1]);
app.showNotification(M.join(‘ ‘));

As you can see, it uses the Office 365 Add-In built-in app.showNotification method to show the result.