Create Sharing Link using CSOM/PnP.Framework

Rohit Devmore 21 Reputation points
2022-09-02T13:24:27.437+00:00

We have a requirement of having Unique/Durable link of sharepoint file, which will be stored in SQL DB by Job Scheduler (exe app). Documents might be moved to different folders within a site hence absolute URL cannot be trusted.
We have two options

  1. Document ID service = Though its a good options, downside is, this service takes some time to generate Document ID (since timer job generates this)
  2. Use Sharing option. We are exploring this option and came across this post where its answered how to generate sharing link from CSOM = https://learn.microsoft.com/en-us/answers/questions/84801/calling-the-sharelink-sharepoint-rest-api-endpoint.html

237286-image.png

We did try this code however we are always getting unauthorized. context object is generated from PnP. We need to use AppId and Secrete since its unattended scheduled job. Cred object is always showing null.. Any thoughts please?

Digest value and Web title are correct. However, Cleint.Upload call fails. (since Cred is blanks). Can app ID/Secrete not work with this?

237298-image.png

    using Microsoft.SharePoint.Client;  
    using Newtonsoft.Json;  
    using PnP.Framework;  
    using System;  
    using System.Net;  
      
    namespace SP_ConsoleApp  
    {  
        class Program  
        {  
            static void Main(string[] args)  
            {  
                string siteUrl = "https://dsds.sharepoint.com/sites/devstuff";  
                string clientId = "6ab77591-088a-447a-b406-23aadf9ae721";  
                string clientSecret = "afopU4VxvYDigYXW8K7tLOWONsdsdst9x3GFKOvr0Ng05lSM=";  
      
      
      
                //For SharePoint app only auth, the scope will be the SharePoint tenant name followed by /.default  
                var scopes = new string[] { "https://dsds.sharepoint.com/.default" };  
      
                using (var cc = new PnP.Framework.AuthenticationManager().GetACSAppOnlyContext(siteUrl, clientId, clientSecret))  
                {  
                    cc.Load(cc.Web, p => p.Title);  
                    cc.ExecuteQuery();  
                    Console.WriteLine(cc.Web.Title);  
      
                    var web = cc.Web;  
                    var dig = cc.GetFormDigestDirect();  
      
                    cc.Load(web);  
                    cc.ExecuteQuery();  
      
                    Console.WriteLine($"{web.Title}--{dig.DigestValue}");  
      
                    ShareFile(cc, cc.Credentials as SharePointOnlineCredentials, dig.DigestValue);  
                    Console.ReadKey();  
                     
      
                };  
            }//main  
            private static void ShareFile(ClientContext context, SharePointOnlineCredentials creds, string digest)  
            {  
                try  
                {  
                    string szRequestURL = @"https://dsds.sharepoint.com/sites/devstuff/_api/web/GetFileByUrl(@v)/ListItemAllFields/ShareLink?@v='/sites/devstuff/testLib/Document1.docx'";  
      
                    string response = "";  
                    using (var client = new WebClient())  
                    {  
                        client.Credentials = creds;  
                        client.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");  
                        client.Headers.Add(HttpRequestHeader.ContentType, "application/json;odata=verbose");  
                        client.Headers.Add(HttpRequestHeader.Accept, "application/json;odata=verbose");  
                        client.Headers.Add(HttpRequestHeader.UserAgent, "Mozilla/4.0+(compatible;+MSIE+5.01;+Windows+NT+5.0");  
                        client.Headers.Add("X-RequestDigest", digest);  
      
                        var endpointUri = new Uri(szRequestURL);  
      
      
                        response = client.UploadString(szRequestURL, "{\"request\":{\"createLink\":true,\"settings\":{\"allowAnonymousAccess\":true,\"linkKind\":2,\"expiration\":null,\"restrictShareMembership\":false,\"updatePassword\":false,\"password\":\"\", \"description\":\"My description\", \"role\":8,\"applicationLink\":false,\"limitUseToApplication\":false}}}");  
                        dynamic dynObj = JsonConvert.DeserializeObject(response);  
                        if (dynObj == null)  
                        {  
                            return;  
                        }  
                        string szURL = dynObj.d.ShareLink.sharingLinkInfo.Url.Value;  
                        Console.WriteLine("Sharing link: " + szURL);  
                    }  
                }  
                catch (Exception e)  
                {  
                    Console.WriteLine("Error sharing files: " + e.ToString());  
                }  
            }  
        }//cs  
    }//ns  
      
SharePoint
SharePoint
A group of Microsoft Products and technologies used for sharing and managing content, knowledge, and applications.
10,677 questions
SharePoint Development
SharePoint Development
SharePoint: A group of Microsoft Products and technologies used for sharing and managing content, knowledge, and applications.Development: The process of researching, productizing, and refining new or existing technologies.
2,970 questions
SharePoint Server Development
SharePoint Server Development
SharePoint Server: A family of Microsoft on-premises document management and storage systems.Development: The process of researching, productizing, and refining new or existing technologies.
1,608 questions
{count} votes

Accepted answer
  1. Tong Zhang_MSFT 9,226 Reputation points
    2022-09-05T07:26:16.937+00:00

    Hi @Rohit Devmore ,

    According to my research and testing, If I use Client-Id and Client-Secret, I will get the same error as you, but if I use an account and password , the above code works well and generates a share link. Therefore, this code does not appear to apply to Client-Id and Client-Secret.

    As a workaround, you can try to use the following code to create external sharing link:

    class Program  
        {  
            static void Main(string[] args)  
            {  
                string siteUrl = "https://xxxxx.sharepoint.com/sites/zellatest";  
                string clientId = "xxxxxxxxxxxxx";  
                string clientSecret = "xxxxxxxxxxx";  
      
      
      
                //For SharePoint app only auth, the scope will be the SharePoint tenant name followed by /.default  
                var scopes = new string[] { "https://xxxxx.sharepoint.com/sites/zellatest" };  
      
                using (var cc = new PnP.Framework.AuthenticationManager().GetACSAppOnlyContext(siteUrl, clientId, clientSecret))  
                {  
                    cc.Load(cc.Web, p => p.Title);  
                    cc.ExecuteQuery();  
                    Debug.WriteLine(cc.Web.Title);  
      
                    var web = cc.Web;  
                    var dig = cc.GetFormDigestDirect();  
      
                    cc.Load(web);  
                    cc.ExecuteQuery();  
      
                    string link = cc.Web.CreateAnonymousLinkForDocument("https://xxxx.sharepoint.com/sites/zellatest/test/Document.docx", ExternalSharingDocumentOption.View);  
                    Debug.WriteLine(link);  
                };  
            }//main  
              
        }  
    

    My test result:
    237717-01.png


    If the answer is helpful, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.



0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.