O365 OneNote API in Web Application

Microsoft recently announced OneNote API for O365 notebooks. I decided to give it a try but most of the examples/documentation I found was for native client applications which is obviously not working for web apps. After spending a lot of time on it and getting help from Microsoft OneNote API team, I was able to resolve it. Below are the steps you need to follow to access your notebooks using OneNote API for O365. Please note that the below code is for single tenant app and OneNote API are in preview.

  1. Register your application in Azure AD: We need to register the app in Azure AD as well as give OneNote API proper permissions. The steps are as follows:
    • Go to Azure AD related to your O365 account

      Azure AD
    • Navigate to Active Directory and click on Applications tab. Add a new application and select “Add an application my organization is developing”NewApplication
    • Give proper name to the app and select Web Application/OR Web API optionWebAppORWebAPI
    • Provide a Sign-On URL and a unique App ID URI.
      • Sign-On URL: https://localhost:44327/
      • APP ID URI: https://<tenantname>.sharepoint.com/SingleTenantOneNoteAPIDemo, replace <tenantname> with the name of your Office365 tenant.
    • Now the new application is ready. Go to “Configure” tab and at the bottom you will get the option to manage permissions. Azure AD already has “Enable sign-on and read user’s profiles” permission.ExistingPermissions
    • Click on “Add application” and select “OneNote” and give appropriate permission.OneNotePermission
    • In “Keys” area select 2 years. You will get a message that “The Key value will be displayed after you save it”. Make sure to copy this key value as this is client secret for your application. Also, copy the client id.Keys/ClientSecret
    • Now go to “Reply URL” and add a new one which will correspond to the address in which you will write the code to handle the return flow.ReplyURL
    • Click on “Save” and DON’T FORGET TO COPY KEY VALUE AND CLIENT ID. That’s it, your application is configured in Azure AD now.
  2. Access OneNote API in code
    • Open Visual Studio -> Click on “New Project” -> Select ASP.NET Web Application and give a proper name to your application. Click on OK.
    • In the next screen, select “Change Authentication” and click on “Organization Accounts”. Provide domain name of your O365 account as well as APP ID URI which you used while configuring the app in Azure AD.ChnageAuthentication
    • Click on “OK” and you will be asked to login to the O365 account. Login using the account you used while creating the entry in Azure AD and hit “OK”.
    • Your project will be set up. Open the web.config and you will notice tenant related entries. In the “appsettings” section enter the other details like client id and app key. You can directly use these in code or add them in web.config. I usually prefer web.configweb.config
    • Add nuget for ADAL in your project.ADAL
    • The code for accessing the OneNote API is given below. Please note, that here I am using AcquireTokenByAuthorizationCodeAsync method for authorization.

This is just basic code which will return all your notebooks. You can also create/edit the notebooks based on the permissions you provided to the application in Azure AD. You can change these permissions later.

My next step is to achieve this in multi-tenant app. As apparent from the code, the authorization URL contains the tenant URL which is not possible in multi-tenant apps. I will soon update the post for this scenario.

Lastly, I would like to thank Microsoft OneNote API team for their help while I was stuck in these issues. Apart from that, please go through Using ADAL’s AcquireTokenBy AuthorizationCode to Call a Web API From a Web App post, it explains the process in more detail.

Hope this helps. Happy coding!

Update Aug 4, 2015: For using OneNote API in multi-tenant app, go through WebApp-WebAPI-MultiTenant-OpenIdConnect-DotNet example. This is for graph API but works as it is for OneNote API too. A very good and self-explanatory sample.

Manage Licenses in O365 using Powershell

Few days back, I got stuck in a weird issue while creating users in O365. For some of the users, the services like SharePoint, Exchange etc. were displaying “setting up…” status. I checked and was informed that it might take up to 4 hours for services to set up but even after 2 days, the issue was not resolved. I tried to remove and assign the license again for one of the user and it started working. As I have lots of users, I can not do it manually so eventually I ended up using powershell.

This post will take you through the process I followed while trying to resolve this issue and also the powershell script.

  1. The first step was to install Microsoft Online Services Sign-In assistant and Windows Azure Active Directory (Azure AD) module for Windows Powershell in my system. Both are 64 bit versions and you can find more details about it here.
  2. After that launch the powershell and connect to the tenant which is facing the issue using the Connect-MsolService command. It will ask for your O365 credentials.
    Powershell Credential Window
  3. To get the AccountSkuId and included ServicePlans for your tenant, you can use the following command:
    Get-MsolAccountSku | Where-Object {$_.SkuPartNumber -eq “yourpackname“} | ForEach-Object{$_.ServiceStatus}
    Account Details
    As you can see in the above screenshot, we now have tenant’s AccountSkuId and all the service plans with their status. Similarly, we can get the status of service plan assigned to all the users. For faulty licence assignment, usually the provisioning status is “Pending Input”.
  4. Next step is to create a CSV of all the users for which this issue is present. Let’s say the name of CSV is UsersList.csv.
  5. Run the below powershell command to remove and assign licenses again:
    $allUsers = Get-Content "{PathofFile}\UsersList.csv"
    :Outer foreach ($user in $allUsers)
    {
      Write-Host($user) -foregroundcolor "magenta"
      $IsFaulty = "false";
      $O365User = Get-MsolUser -User $user
      $Licenses = $O365User.Licenses[0].ServiceStatus
      :Inner foreach($lic in $Licenses) {
         If ($lic.ServicePlan.ServiceName -eq "SHAREPOINTSTANDARD_EDU" -and $lic.ProvisioningStatus -ne "Success")
         {
           $IsFaulty = "true"
            break Inner
          }
     }
     If ($IsFaulty -eq "true")
     {
       Set-MsolUserLicense -User $user -RemoveLicenses {AccountSkuId:screenshot2}
       Set-MsolUserLicense -User $user -AddLicenses {AccountSkuId:screenshot2}
     }
    }
    

The above code first reads all the users from the CSV file. After that it checks their SharePoint service status and reassigns the licence if the status is not equal to “Success”. You can check for any other service which is applicable to you.

The name of services are different for different plans so make sure to execute step 3 for exact service names. One important thing to note here is, if you remove the license, users might lose all of their data. In my scenario, the users were newly created so that was not an issue, but if that is the case don’t run this script.

Hope this helps!

References:

Provider Hosted App – Copy Document across Site Collections

To copy documents across site collections in provider hosted app, we need to perform the following steps:

  1. Provide appropriate permissions to app
  2. Create client context for the source location
  3. Downloading document stream from source
  4. Create client context for the destination
  5. Uploading document to destination (This step is same as mentined in my previous post)

The approach I am going to display will also help if you want to create another site collection context from the existing one.

For the above scenario, please note the following points:

  1. App should have minimum “Write” permission on “Tenant” for the code to work as we are moving document from one site collection to another.
  2. I have used app-only policy. This is used as user might not have write permission on the whole tenant. The only downside is, in “Created By” field, instead of user name, it shows “SharePoint App”. I created a custom column to save actual user name.

Hope this helps. Happy coding!!

 

CSOM – Check If My Site Exists

There are times when we want to know whether My Site exist for a particular user. In general, My Site is created when a user accesses the My Site (i.e. the “About Me” link) for the first time. For more details on My Site architecture check this msdn link.

Using CSOM, we can fetch a particular user’s my site link. The code for that is:

The above code returns my site url of the user but if my site does not exist then also it returns the my site host url of that user. So, in this case the url returned is something like:

https://tenant-my.sharepoint.com/Person.aspx?accountname=accountnameofuser

This does not tell us whether my site actually exist or not unless we do some url manipulation. But there is a peroperty in the same code which returns my site relative url only if it exists and that property is PersonalSpace. This is present in UserProfileProperties of PeopleManager class.

The code to fetch that is :

This will return blank if my site does not exist else will return /personal/email_of_user

P.S. The code above could also be used in apps, just give Read permission to User Profile.

Happy Coding!!

Provider Hosted App – Upload Large Files using CSOM

We all at some time struggled with uploading large files using CSOM in O365. Using managed client object model, we can upload a maximum of 2MB file size. If the file is of larger size, we usually had two options:

  1. File.SaveBinaryDirect
  2. Using REST which supports upto 2GB

The first option can not be used in Sharepoint Online because SaveBinaryDirect does not work with claims authentication (check this link).

Update: We can now use SaveBinaryDirect in SP Online by using SharePointOnlineCredentials class which could be used for authentication of context but I am yet not able to make it work in provider hosted add-in. It works in normal console app by providing credentials though.

Does that mean we are left with REST only? Actually NO. We have one more way by which we can upload files greater than 2MB in O365 using CSOM in provider hosted app. But let’s first see the standard CSOM way which allows us 2MB file upload.

Now the method to upload larger files is exactly the same. We only have to use FileCreationInformation.ContentStream property instead of FileCreationInformation.Content property. The whole code is present below:

In some cases, you might get a FileNotFoundException while using above code. Below is another way to use the code

Note that I replaced FileStream with the input stream present in the uploaded file itself.

P.S. I have tested the above code for files upto 50 MB. It depends largely on internet speed. Once for 50MB file size it gave me time out error (which could be fixed by setting RequestTimeout property of client context)

Hope this helps.

Reference:

  1. O365 AMS

Unique Identifier for O365

Multi-tenant apps are a very common scenario in real world. Whenever we create an app, we mostly target it to multiple tenants for wider reach. There are some cases in which we want to save our app data in custom database instead of app web or host web. These scenarios are very frequent and at that time we need a unique identifier to differentiate among tenants. So my search started for a pre-existing identifier of O365 and ended right at TokenHelper.cs file.
Yes, Microsoft has already provided a code for it, I just didn’t realize it’s a unique identifier. 🙂

In TokenHelper.cs there is a public method GetRealmFromTargetUrl(Uri targetApplicationUri) that takes URI of the target sharepoint site as its parameter. This method actually return a string representation of the realm GUID. According to msdn,

 Realm is unique to each tenant in Office 365 or to each SharePoint farm on-premises. It is possible to discover the realm at run time. So, it is not necessary to cache this information between requests, but it will cost you an extra round trip to SharePoint each time you want to look it up. If you use code similar toTokenHelper.GetRealmFromTargetUrl with the site URL, and cache the result per site (or even per site and per user), you can use this later without making the extra call.

For more details, visit this link.

Therefore, above method return a unique id for tenant. You can pass host web uri in it. This id can be saved in database for further use and can even be cached.

Source code for this method is given below. This is copy pasted from TokenHelper.cs class which Visual Studio auto-generates on creating provider hosted app.

 


public static string GetRealmFromTargetUrl(Uri targetApplicationUri)
{
WebRequest request = WebRequest.Create(targetApplicationUri + "/_vti_bin/client.svc");
request.Headers.Add("Authorization: Bearer ");

try
{
using (request.GetResponse())
{
}
}
catch (WebException e)
{
if (e.Response == null)
{
return null;
}

string bearerResponseHeader = e.Response.Headers["WWW-Authenticate"];
if (string.IsNullOrEmpty(bearerResponseHeader))
{
return null;
}

const string bearer = "Bearer realm=\"";
int bearerIndex = bearerResponseHeader.IndexOf(bearer, StringComparison.Ordinal);
if (bearerIndex < 0)
{
return null;
}

int realmIndex = bearerIndex + bearer.Length;

if (bearerResponseHeader.Length >= realmIndex + 36)
{
string targetRealm = bearerResponseHeader.Substring(realmIndex, 36);

Guid realmGuid;

if (Guid.TryParse(targetRealm, out realmGuid))
{
return targetRealm;
}
}
}
return null;
}

 

Hope this helps. 🙂

Knockout.js with Sharepoint 2013 App – Part III

In my previous post, we saw how to add items in a SP list using KO. This post will focus on removing items from a list. The code snippet at the end combines all the three posts. Using it; you can display, add and remove items from list. Besides that we send only updated (i.e. added or removed) data to server side. Going on the same lines, we can implement the “edit” functionality also. Right now, I am skipping it.

For reference, the other two posts are:

  1. Part I – Displaying Data from SP list. 
  2. Part II – Adding Data to SP list.
  3. Part III – Removing Data from SP list. (this one)

To add remove functionality, a “Remove this” link is added after every row in the table. So, the html looks like:

KO-Remove-1

$root.RemoveCountries will update the view model. Here $root is the main view model in the topmost/parent context. It will update the whole table by removing the current row.

“Id” column of sharepoint list is also included in the “CountryList” class to delete items by id. For newly created rows the id is assigned to ‘0’. After every update to the server, the “changedCountries” array is emptied.

The final result will look like,

KO-Remove-2

Now, the final collaborated code is:

 

Note: In sharepoint hosted app, we do not need SP.RequestExecutor.js to communicate with host web that means cross-domain calls to host web is allowed without this javascript file. The code is updated for this.

Summary: KO is an amazing library that makes life easier by segregating the display logic with the business logic. Using it in SP, makes the js code neat and simple to understand. The only flip side is, if there are changes at the server side, then UI is not automatically updated until a refresh is performed. Regardless of this, KO is a library we all should learn.

P.S.: This example is by no means perfect or bug free. There are few loopholes like:

  1. User can edit the existing items but this is not handled in the code.
  2. After adding a new item to SP list the view model is not updated unless user do a refresh.
  3. Only 20 items are fetched and no pagination is implemented.

But the code is for demo purpose only. You can extend it in any way you want. Hope it helps!!

Another good blogs on KO (also referenced here):

  1. Knockout.js Simplified
  2. Using Knockout.js in a sharepoint context

Knockout.js with Sharepoint 2013 App – Part II

In my previous post, we saw how to display items from a sharepoint list using KO. In this post, we will see how to add items in the list. This demo is in continuation with the previous one.

For your reference, the posts in this series are:

  1. Part I – Displaying Data from SP list. 
  2. Part II – Adding Data to SP list. (this one)
  3. Part III – Removing Data from SP list.

First, lets go through the changes made in the previous code for incorporating this functionality.

HTML Changes:

  1. A button “Add State” is added. This button updates the view model and add a new country-state in the existing table. It does not update the SP list.
  2. Another button “Submit to Sharepoint” is added. This button actually updates the data in the sharepoint list.
  3. Now the country and states are displayed in text box so that user can add new ones. Edit functionality is not included in this post.
  4. Two divs are added for displaying success and failure messages.

CSS Changes:

  1. styling is added for success and failure messages. Not much changes are done here.

Javascript Changes:

  1. Another property “IsUpdated” is added in  the “CountryList” class. This property is used to keep tab of newly created items in the view model. Using this, we will send only changed items to the server and not the complete list of data.
  2. In the view model, “UpdateSPList” function is added. This function will be called on click of “Submit to SP” button.
  3. “changedCountries” array holds all the newly added items. “emptyValues” is a boolean variable which maintains if any of the country name or state name is blank. If yes, then that entry is not sent to SP and a message is displayed to the user.
  4. “SubmitDataToSP” is a function which actually uses sharepoint CSOM and adds new items in the list.
  5. On click of “Add State” button a function “AddCountries” of view model is called. The parameters passed are $data (which is the current item inside a foreach loop), country name, state name and true as the value of “IsUpdated” property. For more details on ‘click’ event, check this link.
  6. Similarly on click of “Submit to SP” we call, “UpdateSPList” method of the view model.

So, now the complete code is as follows:

The result page will look like:

result

Note:

Please note that this might not be the completely optimized way to achieve this functionality. The goal here is to demo use of KO with sharepoint. In the next post, we will modify this code further to achieve delete functionality.

Hope this helps!!