Tuesday 6 October 2015

SharePoint 2016 Durable Document Links


One of the new feature available in SharePoint 2016 is Durable Links which provides resource id based links for documents. This feature protects the integrity of document links even if the document is renamed or moved to. When links to documents with resource id are used SharePoint 2016 looks up the document by resource id and opens in Office Online.

An example of how durable link in SharePoint 2016 works

1.    User uploads a document named TestDoc.docx to a document library in SharePoint 2016 sites.

2.    User shares the document to other users in his organization by using Share option in document preview page


3.    An email is sent to users with the link to the document TestDoc.docx.


4.    If you notice the link it will have a reference to the resource id like https://SharePoint Site /Documents/TestDoc.docx?d=wc0309c29bbf74b26be00d97cd54b9a79

5.    Clicking the link will open the document in Office online web app


6.    If the document creator changes the name of the document say to TestDocUpdated.docx the link that was shared earlier will work without breaking as office online loads the document based on the resource id


 

Monday 31 August 2015

SharePoint 2013 and SharePoint 2016 Preview limitations in Edge browser

SharePoint 2013 and SharePoint 2016 Preview has limitations when accessed from Edge the latest and fastest browser from Microsoft that comes with Windows 10. Below are some of the functionality that will not work in SharePoint 2013 and SharePoint 2016 preview when using Edge browser

Drag and Drop for file upload
Files can’t be uploaded to libraries using Drag and Drop. When you try to do so, a not supported icon would be displayed

  
Features that require ActiveX components
Some features in SharePoint require ActiveX components and will not work in Edge browser. These features include Open with Explorer, Open with Access, Open with Project. These options would be disabled on the list\library ribbon



Customize in InfoPath
Clicking Customize in InfoPath from the ribbon would say that you’ll need Internet explorer to use the feature.


Export to Excel will show a warning
Clicking Export to Excel from the ribbon will show a warning stating that you will require compatible application, however the functionality will work.

 
Lync Contact Card
If the user has Lync\skype for business client installed on their machine and they hover over user name in SharePoint, the Lync Contact Card pops up showing information such as email, phone etc. This functionality depends on Active X and doesn’t work with Edge browser.

Thursday 13 August 2015

Visual Studio 2015 Office Developer Tools automatically adds correct version of SharePoint client DLLs based on target SharePoint version


I recently installed Visual Studio 2015 and selected the Office developer tools feature as part of the install. Then I went about creating a sample SharePoint App project. The project creation wizard started with asking for SharePoint site and type of App

Next step required to specify the target SharePoint version. This step is newly added in Visual Studio 2015 and the target SharePoint version is auto selected based on the URL of the SharePoint site mentioned in previous step

As described  in the step Visual Studio 2015 Office Developer Tools adds correct reference to version SharePoint client DLL based on target SharePoint version.

If SharePoint 2013 was selected for target version then visual studio adds reference to version 15.0.0.0 of SharePoint.Client DLL

If SharePoint online was selected for target version then visual studio adds reference to version 16.1.3912.1204 of SharePoint.Client DLL

Friday 31 July 2015

Could not load the assembly 'Microsoft.SharePoint,Version=16.0.0.0’ error when moving sites from Office 365 SharePoint Online to On Premise SharePoint 2013


Recently one of my clients who were using Office 365 SharePoint Online wanted to have a backup of their sites in their on-premise SharePoint environment. I used a leading SharePoint migration tool and was able to back up the sites to on premise SharePoint. But when trying to open a site or a document library I ran into the error “Could not load the assembly 'Microsoft.SharePoint,Version=16.0.0.0’”

The issue happened because Office 365 SharePoint Online is has been updated to version 16 of SharePoint DLL while the on-premise SharePoint 2013 server had version 15 of the DLL. All the pages for sites, libraries and lists were pointing to the version 16 of the DLL.

 If it was single page a quick fix would have been to open the page in SharePoint Designer and change the version of DLL to 15. But since there were many sites and sub sites with lots of libraries and list I wrote a PowerShell script(courtesy http://www.sharepointdiary.com/2013/02/create-update-copy-delete-views-powershell.html) to create new views for all lists and libraries and make them as default views. As the new view pages are referencing version 15 of Sharepoint the sites and libraries sprang back to life.
 


Thursday 11 June 2015

Calling Office 365 Unified API (Preview) from Java script using ADAL for JS

Office 365 unified API provides developers with a single endpoint for accessing all Office 365 data and relationships, including Users, Groups, Files, Mail, Calendar, Contacts and Office Graph. Office 365 Unified API removes the complexity in accessing Office 365 data and makes development simpler. Developers have a choice of calling the REST API or use client libraries that are available for .Net, Android and iOS platforms.  In this blog I’ll explain the process of calling the Office 365 Unified from Java script using ADAL for JS.

For developing a Java script application with Office 365 Unified API the below prerequisites have to be met

1.       Web site development tool of your choice(Visual Studio in my case)
2.       Office 365 Tenant ( Trial subscription can be used)
3.       Microsoft Azure Tenant (Trial subscription can be used).

Note: The Azure subscription should be tied to the Office 365 account.

Once we have the prerequisites ready we can start with development of the application.  The first step is to register the application Azure.

Register the application Microsoft Azure

  1. Logon to Azure Management Portal, using your Azure AD credentials.
  2. Click Active Directory on the left menu, then select the directory for your Office 365 tenant.
  3. Click Applications from the top menu.
  4. Click Add from the bottom tray.
  5. On the What do you want to do? page, select Add an application my organization is developing.
  6. On the Tell us about your application page, enter the application name as O365UnifiedAPIWithJavaScript and select the type as Web application and/or web API.
  7. Click the arrow on the bottom right to move to next page.
  8. On the Application information page, specify the app SIGN-ON URL and APP ID URI and then click the tick mark on bottom right. The SIGN-ON URL is our app's web address including the port number. For example http://localhost:55389/start.html.  For the App ID URI, enter https://<tenant_name>/O365UnfiedAPIWithADALJS where <tenant_name> is the name of Azure AD tenant.
  9. Once the application has been added, you will be taken to the Quick Start page for the application. From the application page, click Configure from the top menu.
  10. Copy the value specified for Client ID on the Configure page and save it to notepad or similar tool.
  11. Click Add application button under permissions to other applications section and in the dialog box that opens, select the Office 365 unified API (preview) application and click the tick mark on bottom right.
  12. On the application configuration page, select Office 365 unified API (preview) and select Read users’ files permission.
 
 13. Click Save in the bottom menu.

Now that the app has been registered in Azure we can start developing the Java Script application. For this example I will be using a Java Script application that lists files from users One Drive.

1.       Start Visual Studio and create an empty ASP.Net web project.
 
2.       Add a new HTML file to the project and name it as start.html. Add button input elements to the page for login, logout and showing files. Add pre elements for showing the result, error and loading message.

3.       The content of start.html will be similar to

<html>
<head>
    <title>Office 365 Unified API and ADAL JS</title> 
</head>
<body >

    <div>
        <input type="button" id="btnLogin" value="Login">
        <input type="button" id="btnLogout" value="Logout" hidden>
        <br />
        <pre id="lblUser"></pre>
        <input type="button" id="btnFiles" value="Show Files" hidden>
        <br />
        <pre id="lblLoading" hidden>Loading Files...</pre>
        <pre id="lblFiles" hidden></pre>
        <pre id="lblError" hidden></pre>
    </div>
    <br />
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script src="https://secure.aadcdn.microsoftonline-p.com/lib/1.0.0/js/adal.min.js"></script>
    <script src="Scripts/app.js"></script>
</body>
</html>
 
4.       Add reference to ADAL. and JQuery JS from CDN source

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<script src="https://secure.aadcdn.microsoftonline-p.com/lib/1.0.0/js/adal.min.js"></script>
5.       Add a java script file with the name app.js to the project. This file will have the code that connects to office 365 unified API via ADAL and list the files from users One Drive.
6.       adal.js exposes a class AuthenticationContext that handles the authorization and token acquisition process. Within our app.js we initialize the AuthenticationContext class by passing the configuration values
      configuration = {

        tenant: '<tenant_name>',

        clientId: '<client_ID>',

        postLogoutRedirectUri: '<redirect URL>',

        endpoints: 'https://graph.microsoft.com',

        cacheLocation: 'localStorage',

      };

      var authContext = new AuthenticationContext(configuration);
In the code above tenant is <tenant_name> is the name of Azure AD tenant, <client_ID> is the client ID of the App we have copied from Azure App configuration page, <redirect URL> is the url to which the Azure will redirect after login.

7.       Then we create a method called ShowFiles that will be invoked with the show files button on the HTML page is clicked.  Within this method will write code to call the Office 365 unified API end point https://graph.microsoft.com to acquire token and the use to token to make subsequent call to the files endpoint https://graph.microsoft.com/beta/me/files . If the call to files endpoint is successful we loop through the response to form a HTML table that lists the files.

8.       The complete code in app.js will be similar to

(function () {
      configuration = {
        tenant: 'tenant_name',
        clientId: 'client_id',
        postLogoutRedirectUri: 'redirect url',
        endpoints: 'https://graph.microsoft.com',
        cacheLocation: 'localStorage', // enable this for IE, as sessionStorage does not work for localhost.
      };

      var authContext = new AuthenticationContext(configuration);

    var $loginButton = document.getElementById("btnLogin");
    var $logoutButton = document.getElementById("btnLogout");
    var $filesButton = document.getElementById("btnFiles");
    var $lblUser = document.getElementById("lblUser");

    // Handle Redirect From AAD After Login
    var isCallback = authContext.isCallback(window.location.hash);
    authContext.handleWindowCallback();
    //$errorMessage.html(authContext.getLoginError());

    if (isCallback && !authContext.getLoginError()) {
        window.location = authContext._getItem(authContext.CONSTANTS.STORAGE.LOGIN_REQUEST);
    }

    // Hide and show elements based on login status
    var user = authContext.getCachedUser();
    if (user) {
      
        $loginButton.hidden = true;
        $logoutButton.hidden = false;
        $filesButton.hidden = false;
        $lblUser.innerText = "Welcome " + user.profile.name;
    } else {
    
        $loginButton.hidden=false;
        $logoutButton.hidden = true;
        $filesButton.hidden = true;
        $lblUser.innerText = "";
    }

 //Add event handlers for button clicks
    $loginButton.onclick = function () {
                authContext.login();
    };

    $logoutButton.onclick = function () {
        authContext.logOut();
    };

    $filesButton.onclick = function () {
        ShowFiles();
    };

    //Get files from OneDrive and list in a table
    function ShowFiles() {
        // Empty old view contents.
        var $lblLoading = document.getElementById("lblLoading");
        var $lblError = document.getElementById("lblError");
        $lblLoading.hidden = false;
                console.log("Fetching files from OneDrive...");
        // Acquire token for Files.
                authContext.acquireToken('https://graph.microsoft.com', function (error, token) {

                    // if there is an error in ADAL
                    if (error || !token) {
                        $lblError.innerText = 'ADAL exception : ' + error;
                        
                        return;
                    }
                    $.ajax({
                        type: "GET",
                        url:  "https://graph.microsoft.com/beta/me/files",
                        headers: {
                            'Authorization': 'Bearer ' + token,
                        }
                    }).done(function (response) {

                        var output = '<table cellspacing="0" cellpadding="5" border="1"><tr><th>File Name</th><th>Type</th></tr>';
                        //Loop through response and form files HTML output
                        response.value.forEach(function (item) {                         
                            output += "<tr><td>" + item.name + "</td><td>" + item.type + "</td></tr>";
                        })
                        output += "</table>";
                        var $lblFiles = document.getElementById("lblFiles");
                        $lblLoading.hidden = true;
                        $lblFiles.innerHTML = output;
                        $lblFiles.hidden = false;
                        $filesButton.hidden = true;
                    }).fail(function () {
                        console.log('Problem in fetching files from OneDrive.');
                        $lblError.innerText = 'Problem in fetching files from OneDrive.';
                        $lblError.hidden = false;    
                    });
                });
    }
}());
 
9.       Add a reference to app.js in start.html

10.   Now if we open start.html in a browser a login button will be displayed clicking which will redirect to Azure login page. After successful authentication we will be taken back to start.html in our web application and the Show Files button will be displayed.

11.   Clicking the Show Files button will list the files stored in One Drive for the logged in user as shown below.

Friday 29 May 2015

Calling Office 365 Unified API(Preview) from .Net Native Application

The Office 365 unified API provides developers with a single endpoint for accessing all Office 365 data and relationships, including Users, Groups, Files, Mail, Calendar, Contacts and Office Graph. Office 365 Unified API removes the complexity in accessing Office 365 data and makes development simpler. Client libraries to access Office 365 API are available for .Net, Android and iOS platforms.  I’ll explain the process of developing a sample application using the Office 365 Unified API client library for .Net platform. 

For developing a .Net application with Office 365 Unified API client library the below prerequisites have to be met 

1.       Visual Studio 2013 or higher

2.       Office 365 Tenant ( Trial subscription can be used)

3.       Microsoft Azure Tenant (Trial subscription can be used).  

Note: The Azure subscription should be tied to the Office 365 account.
Once we have the prerequisites ready we can start with development of .net application.  The first step is to register the application we are developing in Azure.

Register the application Microsoft Azure

  1. Logon to Azure Management Portal, using your Azure AD credentials.
  2. Click Active Directory on the left menu, then select the directory for your Office 365  tenant.
  3. Click Applications from the top menu.
  4. Click Add from the bottom tray.
  5. On the What do you want to do? page, select Add an application my organization is developing.
  6. On the Tell us about your application page, enter the application name as O365UnifiedAPITest and select the type as NATIVE CLIENT APPLICATION.
  7. Click the arrow on the bottom right to move to next page.
  8. On the Application information page, specify http://localhost/Office365APITest as Redirect URI, and then click the tick mark on bottom right.
  9. Once the application has been added, you will be taken to the Quick Start page for the application. From the application page, click Configure from the top menu.
  10. Copy the value specified for Client ID on the Configure page and save it to notepad or similar tool.
  11. Click Add application button under permissions to other applications section and in the dialog box that opens, select the Office 365 unified API (preview) application and click the tick mark on bottom right.
  12. On the application configuration page, select Office 365 unified API (preview) and select Read directory data permission.
  13. Click Save in the bottom menu.
After registering the application in Azure we can go about developing our .Net application. For this example I will be using a Windows Form application that displays user details in a grid.

1.       Fire up Visual Studio 2013 and create a new Windows Form application.

2.       Add the below the Office 365 Unified API client library and dependencies from NuGet packages
    1. Active Directory Authentication Library
    2. Office 365 unified API client library (preview)
    3. Microsoft OData Proxy Extensions Library for .NET
       3.       Add a button and data grid to the Windows Form

4.       Add the below code to the button click event to initialize Office 365 unified API client

Uri O365APIURI= new Uri(APIRootURL);

       Microsoft.Graph.GraphService graphclient = new

        Microsoft.Graph.GraphService(O365APIURI,   async () => await GetToken());

APIRootURL is the URL of the Office 365 Unified API which is of the form


 
5.       GetToken function passed in the GraphService constructor gets the access token for our application and prompting for Azure credentials.  The function will be implemented as below

public async Task<string> GetToken()

        {
            var redirectUri = new Uri(RedirectURL);

            AuthenticationContext authenticationContext =

            new AuthenticationContext(LoginUrl, false);

            if (AuthToken == "")

            {
                AuthenticationResult AuthnResult = authenticationContext.AcquireToken(

                             ResourceUrl,

                             AppClientId,

                             RedirectUri,

                             PromptBehavior.Always
                         );

                AuthToken = AuthnResult.AccessToken;

            }
            return AuthToken;

        }
In this code above, the AuthenticationContext class is exposed by ADAL for .NET and handles the authorization and token acquisition process. LoginUrl is the URL of the Azure login page which is https://login.microsoftonline.com/common. Next we call the AcquireToken method on the AuthenticationContext object and pass ResourceUrl, AppClientId and RedirectUri as parameters. The RedirectUri is the REPLY URI and AppClientId is the CLIENT ID of the app we have configured for the app in Azure during application registration process. ResourceUrl is a string with value of "https://graph.microsoft.com”.

The AcquireToken method will display the Azure login page and prompt for credentials. After successful sign in to Azure, the access token is acquired and can be used in subsequent calls to the Office 365 unified API.

6.       Next create a method that will get the list of users from Office 365 whose type is Member. The method will be implemented as below
public async Task<List<IUser>> GetUsersAsync(Microsoft.Graph.GraphService client)

        {
            List<IUser> userList = null;

            var graphClient = client;

             var userResult = await graphClient.users.Where(u => u.userType == "Member").ExecuteAsync();

             userList = userResult.CurrentPage.ToList();

             return userList;
   }

In the code above ExecuteAsync method fetches the users and the where clause is used to filter only members. 

7.       We then invoke the GetUsersAsync method from button click event and bind the result to data grid.
  List<IUser> userList  = await GetUsersAsync(graphclient);
dataGridView1.DataSource = userList;

8.       When we execute the application and hit the button, user will be prompted to Azure login and after successful login user list will be displayed in the data grid.


We saw an example of calling Office 365 Unified API from a .Net native application. Office 365 Unified API provides many other options for accessing and manipulating data from Office 365 services. Click here to for the complete reference of Office 365 Unified API.