sharepoint integration

How to integrate SharePoint with Salesforce?

This is the era of the cloud. Everything everywhere is connected with each other via cloud-hosted web services and people can access these services from anywhere in the globe, anytime. Such are the powers of the cloud. But is everything really connected as is expected?

Not every cloud-based service can be connected with every other service, but fortunately, most popular Apps can be integrated. And so can Salesforce and Microsoft SharePoint be integrated – two of the most popular Software-as-a-Service (SaaS) products.

However, it is not that simple. In this post, we are going to discuss different ways by which you can integrate Salesforce with SharePoint. But first, let us identify why would you even need to integrate the two?

Why Salesforce SharePoint Integration?

SharePoint is a very robust content management and document management platform used by all kinds of companies, mainly for storing business-related documents and content. It is mostly used as a secure document repository for intranet portals, websites, cloud-based services, and of course as an independent repository as well. However, it is mostly used by businesses using other Microsoft Office products like Excel and Word to create documents. Now since they belong to the same product family, the created documents can be easily exported to SharePoint.

Salesforce on the other hand is a huge SaaS platform used by millions of companies to manage their business processes. It mainly started as a Customer Relationship Management Platform but thanks to its versatility regarding integrations and extensions along with a boost in its ever-growing list of features, it has evolved into a complete sales, marketing, and support business process management platform and can be used for many many kinds of analysis for businesses.

However, it was never known for its document storage capabilities. You can store documents there but it charges quite high fees for storage and is not as robust as Microsoft 365 in this aspect.

So why not simply integrate the two? Most companies having a Microsoft 365 account don’t want to spend more on Salesforce storage. So integration remains the best option.

Salesforce SharePoint Integration Using Microsoft Azure Service

There are a number of ways you can integrate SharePoint with Salesforce. However, Microsoft has not released an API to facilitate direct Salesforce SharePoint interactions so we need to involve a third-party adapter or service. The different ways are:

  • Integrating using a third party system installed adapter
  • Integrating using a Microsoft Azure-hosted service.
  • Integrating using a third-party integration service.

The first way involves building a third-party adapter that had to be physically installed on a computer system and therefore severely limits the cloud-based capabilities. The third way involves using a paid or even free integration service, it is easy to use but it is not as flexible as a custom adapter and may prove to be a security risk. Moreover, the main point of integration was to save cost so paying to save cost needs to properly analyzed.

So the best cloud integration method left is to use a Microsoft Azure-hosted service to integrate your Salesforce and SharePoint.

This method involves multiple steps:

  • Step 1: Salesforce sends authentication requests to the Adapter.
  • Step 2: The Adapter passes on the request to SharePoint.
  • Step 3: SharePoint authenticates the information and passes on a security token for further use.
  • Step 4: The adapter receives the token and passes on the token to Salesforce.
  • Step 5: Using the token as an authentication key, Salesforce then sends a request to view specific or all accessible files and folders.
  • Step 6: The Adapter passes on the request along with the token and receives an output which it again passes on to the Salesforce installation.
  • Step 7: Either the token expires and the process is repeated again, or using the same token more requests are sent and received.

salesforce sharepoint

It seems simple when I present the steps like this but in reality, if the coder is experienced and careful it’s just as simple.

dont miss out iconDon't forget to check out: Multipart/form-Data in Salesforce Integration | The Developer Guide

How Salesforce Performs Step 1

The main point for cloud-based integration is to host a running service on Microsoft’s cloud app platform Azure, and leveraging it to interact with SharePoint. Since the service is hosted on a cloud platform, we usually access it via a web-based URL. So our methods from the Salesforce side to request authentication token look something like this:

public static String getToken(){
    String token;
    if(!Test.isRunningTest()){
        token = SharePointAPIUtility.SharePointAPIGet('<a class="vglnk"                    href="http://testingalgoworks.azurewebsites.net/Api/Values/GetAuthToken" rel="nofollow"><span>http</span>  <span>://</span><span>testingalgoworks</span><span>.</span><span>azurewebsites</span><span>.</span>  <span>net</span><span>/</span><span>Api</span><span>/</span><span>Values</span><span>/</span> <span>GetAuthToken</span></a>','[email protected]','TestingPassword');
    }
    system.debug('token>>> '+token);
    if(token != null){
        return EncodingUtil.urlEncode(token.replaceAll('"',''), 'UTF-8');
    }
    return null;
}
public static String SharePointAPIGet(String endpointUrl,String username, String password){
    try{
    HttpRequest httpRequestObject = new HttpRequest();
    httpRequestObject.setEndPoint(endpointUrl);
    httpRequestObject.setmethod('GET');
    Blob headerValue = Blob.valueOf(username + ':' + password);
    String authorizationHeader = 'BASIC ' + EncodingUtil.base64Encode(headerValue);
    httpRequestObject.setHeader('Authorization', authorizationHeader);
    httpRequestObject.setTimeout(120000);
    system.debug('httpRequestObject>> '+httpRequestObject);
    Http http = new Http();
    HttpResponse httpResponse ;
    if(!test.isRunningTest())
    httpResponse = http.send(httpRequestObject);
    if(httpResponse != null && httpResponse.getStatus() == 'OK' && httpResponse.getStatusCode() == 200){
        system.debug('httpResponse.getBody();>>>>'+httpResponse.getBody()+'httpResponse.getBody();>>>>');
        return httpResponse.getBody();
    }else if(httpResponse != null){
        return 'SharePoint Server Error: Status '+ httpResponse.getStatus()+' Status Code '+                           httpResponse.getStatusCode() +' Body '+httpResponse.getBody();
    }
}catch(CalloutException ce){
    throw ce;
}catch(Exception ex){
    throw ex;
}
    return null;
}

This code hits the Azure service using the URL and receives the authentication token which the Azure service sends.

We will come to steps 2,3 and 4 right after the 5th,

How Salesforce Performs Step 5

Once Salesforce has an authentication token, it uses that to request files and folders from the adapter. Once again it uses the Azure service URL to hit the service.

Here’s a method to request files and a method to request folders.

public static List<String> getAllFolders(SharePoint365APIParser objSharePoint365APIParser){
    try{
        list<String> objFolders = new list<String>();
        if(objSharePoint365APIParser.folders != null && objSharePoint365APIParser.folders.size()>0)//null check
        for(SharePoint365APIParser.folders sp:objSharePoint365APIParser.folders){
            objFolders.add(sp.name);
        }
        return objFolders;
    }catch(Exception ex){
        throw ex;
    }
    return null;
}
public static List<String> getFilesByFolder(String folderName, SharePoint365APIParser objSharePoint365APIParser){
    //if(!test.isRunningTest()){
        try{
            if(objSharePoint365APIParser.folders != null && objSharePoint365APIParser.folders.size()>0)
            for(SharePoint365APIParser.folders sp:objSharePoint365APIParser.folders){
                if(sp.name.equalsIgnoreCase(folderName)){
                    if(sp.files.size() > 0){
                        return sp.files;
                    }else{
                        return new list<String>();
                    }
                }
            }
        }catch(Exception ex){
            throw ex;
        }
        //
    }//end running test loop
    return null;
}

How Azure Performs Step 2, 3, and 4

Once Salesforce has sent the request for an authentication token, here’s how the Azure platform service authenticates login.

[HttpPost]
public bool Login(string email, string password)
{
    //throw new Exception("This is error!!");
    bool validateLogin = false;
    List<string> MessageList = new List<string>();
    //string decryptedPassword = Encryption.Decrypt(encryptedPassword);
    if (email == ConfigurationManager.AppSettings["Email"] && password ==         ConfigurationManager.AppSettings["Password"])
    {
        string authInfo = email + ":" + password;
        authInfo = Convert.ToBase64String(System.Text.Encoding.Default.GetBytes(authInfo));
        //authInfo = Encryption.Encrypt(authInfo);
        System.Web.HttpContext.Current.Response.AppendHeader("Authorization", "Basic " + authInfo);
        // Insert User Token
        MessageList.Add("Login Successful");
        validateLogin = true;
    }
    else
    {
        MessageList.Add("Invalid Username Or Password");
    }
    return validateLogin;
}

How Azure service handles Step 6

Now that Salesforce has an authentication token and is logged in on SharePoint, here’s how our Azure service parses the request for file and folder lists.

[AuthorizeWebAPI()]
[HttpGet]
public Folders GetResourceData()
{
    Folders fld = new Folders();
    try{
        using (ClientContext clientContext = new ClientContext("<a class="vglnk"  href="https://yourprojectname.SharePoint.com/Resources" rel="nofollow"><span>https</span><span>://</span><span>yourprojectname</span><span>.</span><span>SharePoint</span><span>.</span><span>com</span><span>/</span><span>Resources</span></a>")){
            SecureString passWord = new SecureString();
            foreach (char c in "TestPassword".ToCharArray()) passWord.AppendChar(c);
            clientContext.Credentials = new SharePointOnlineCredentials("[email protected]", passWord);
            Web rootweb = clientContext.Web;
            var folders =
            rootweb.GetFolderByServerRelativeUrl("/Resources").Folders;
            string pString = @"Resources";
            clientContext.Load(folders);
            clientContext.ExecuteQuery();
            fld.folders = new List<Folders>();
            fld.name = "Resources";
            foreach (Microsoft.SharePoint.Client.Folder myFolder in folders){
                fld.folders.Add(GetFoldersAndFiles(myFolder, clientContext, pString));
            }
        }
    }
    catch (Exception){ fld.name = "Some error happened."; }
    return fld;
}
private Folders GetFoldersAndFiles(Microsoft.SharePoint.Client.Folder mainFolder, ClientContext clientContext, string pathString){
    Folders fldr = new Folders();
    List<string> fls = new List<string>();
    fldr.folders = new List<Folders>();
    clientContext.Load(mainFolder, k => k.Files, k => k.Folders);
    clientContext.ExecuteQuery();
    foreach (var folder in mainFolder.Folders){
        string folderPath = string.Format(@"{0}{1}", pathString, folder.Name);
        if (folder.Name != "Forms")
        fldr.folders.Add(GetFoldersAndFiles(folder, clientContext, folderPath));
    }
    foreach (var file in mainFolder.Files){
        fls.Add(file.Name);
    }
    fldr.files = fls;
    if (mainFolder.Name != "Forms")
    fldr.name = mainFolder.Name;
    return fldr;
}

As you may see, we have saved all our content on SharePoint as resources and the service retrieves the data from that resource folder.

How To Display SharePoint Files

Now the integration won’t be as effective if we are not able to display the retrieved files somewhere. In our experience, it is best to retrieve files using Salesforce and create a separate Visualforce page to display the retrieved files. Using SharePoint’s inbuilt features it is very easy to display retrieved files. You just have to embed a single line of code in your Visualforce page.

Embedded office control

<embed src="<a class="vglnk" href="https://view.officeapps.live.com/op/view.aspx?src=filepath%2FWebsite%20Requirements.docx" rel="nofollow"><span>https</span><span>://</span><span>view</span><span>.</span><span>officeapps</span><span>.</span><span>live</span><span>.</span><span>com</span><span>/</span><span>op</span><span>/</span><span>view</span><span>.</span><span>aspx</span><span>?</span><span>src</span><span>=</span><span>filepath</span><span>%</span><span>2FWebsite</span><span>%</span><span>20Requirements</span><span>.</span><span>docx</span></a>" width=800px height=500px></embed>

To retrieve a single file you would also need your Azure service. That code would look something like this:

public ActionResult DisplayFile(string filePath, string token){
    try{
        var decrypt = new Encryption();
        DateTime dt = new DateTime();
        if (DateTime.TryParse(decrypt.Decrypt(token), out dt)){
            if (DateTime.UtcNow.Subtract(new TimeSpan(0, 3, 0)) < dt &&
            DateTime.UtcNow.Add(new TimeSpan(0, 3, 0)) > dt){
                var filename = Path.GetFileName(filePath);
                var dirName = Path.GetDirectoryName(filePath);
                var contentType = "application/octet-stream";
                var localFilePath = Server.MapPath("~/SharedDownloads/");
                var localFileName = DateTime.Now.ToString("yyyyMMddHHmmssfff") + "_" + filename;
                var wholePath = Path.Combine(localFilePath, localFileName);
                ValuesController api = new ValuesController();
                (from f in new DirectoryInfo(localFilePath).GetFiles()
                where f.CreationTime < DateTime.Now.Subtract(TimeSpan.FromMinutes(30))
                select f).ToList()
                .ForEach(f => f.Delete());
                using (ClientContext clientContext = new ClientContext("<a class="vglnk"  href="https://yourprojectname.SharePoint.com/Resources" rel="nofollow"><span>https</span><span>://</span><span>yourprojectname</span><span>.</span><span>SharePoint</span><span>.</span><span>com</span><span>/</span><span>Resources</span></a>")){
                    SecureString passWord = new SecureString();
                    foreach (char c in "TestPassword".ToCharArray()) passWord.AppendChar(c);
                    clientContext.Credentials = new SharePointOnlineCredentials("[email protected]", passWord);
                    Web rootweb = clientContext.Web;
                    Microsoft.SharePoint.Client.File file = rootweb.GetFileByServerRelativeUrl(filePath);
                    clientContext.Load(file);
                    clientContext.ExecuteQuery();
                    contentType = GetMimeType(Path.GetExtension(filePath));
                    api.DownloadFile(clientContext, filePath, localFilePath, localFileName);
                }
                return View(new FileModel { FileName = "/SharedDownloads/" + localFileName, ContentType = contentType });
            }
        }
    }
    catch (Exception){
        return View(new FileModel { FileName = "Error" });
    }
    return View(new FileModel { FileName = "Error" });
}

dont miss out iconCheck out another amazing blog by Algoworks here: How To Integrate Salesforce And SharePoint Online Through Files Connect?

Using Salesforce Files Connect

Salesforce and Microsoft, in an obvious strategy of the mutual benefit, went into an extended partnership. On December 17 Salesforce launched its new features via Salesforce Files Connect. It was released after much research and is touted as a method to integrate Microsoft 365 products as well as Microsoft OneDrive. For CRM license holders this service is available for free in a limited capacity of course and can be used to integrate Salesforce with SharePoint directly. But since it’s a new service it’s still not tested for the most optimum performance and security standards by third-party users. We here at Algoworks have immense experience with such third party service integration services- both system-based and Azure service-based. We can safely assume that in the near future Files Connect would be the dominant way to integrate both SaaS platforms.

Responses

Popular Salesforce Blogs