Unable to Debug Remote Event Receiver using Ngrok reverse proxy. ClientContext will be null + Error “iisexpress.exe has exited with code -1”

I want to test and debug a remote event receiver for my custom list inside sharepoint online. So i did these steps:-

  1. Inside our sharepoint online i created a new developer site collection.

  2. using Visual Studio pro 2015 >> i create a new Visual Studio project of type SP Add-in.

  3. The type = provider-hosted, as follow:- enter image description here

  4. after that i changed the Handle Add-in installed/uninstalled to True:- enter image description here

  5. then i open the Ngrok command line, i enter the following:-

ngrok http –host-header=rewrite 50452// where this port is our RER port inside visual studio

where 50452 is the port for the VS project:- enter image description here

i got the following:- enter image description here

so i updated the AappManifest.xml with the forwarding url:- enter image description here

  1. I update the app permission as follow:- enter image description here

  2. then i run the project >> i got this popup >> i select the custom list named “projects”:- enter image description here

  3. where i got to the break-point inside my code >> but the client content inside my code will be empty:- enter image description here

  4. after that the VS stop running and i got this error:- enter image description here

Here is the full code inside my “AppEventReceiver.svc”

public class AppEventReceiver : IRemoteEventService     {         private const string ReceiverName = "ItemAddedEvent";         private const string ListName = "projects";         /// <summary>         /// Handles app events that occur after the app is installed or upgraded, or when app is being uninstalled.         /// </summary>         /// <param name="properties">Holds information about the app event.</param>         /// <returns>Holds information returned from the app event.</returns>         public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties)         {             SPRemoteEventResult result = new SPRemoteEventResult();              switch (properties.EventType)             {                 case SPRemoteEventType.AppInstalled:                     HandleAppInstalled(properties);                     break;                 case SPRemoteEventType.AppUninstalling:                     HandleAppUninstalling(properties);                     break;                 case SPRemoteEventType.ItemAdded:                     HandleItemAdded(properties);                     break;             }               return result;         }         private void HandleAppUninstalling(SPRemoteEventProperties properties)          {              using (ClientContext clientContext =                TokenHelper.CreateAppEventClientContext(properties, false))              {                  if (clientContext != null)                  {                      List myList = clientContext.Web.Lists.GetByTitle(ListName);                      clientContext.Load(myList, p => p.EventReceivers);                      clientContext.ExecuteQuery();                        var rer = myList.EventReceivers.Where(                          e => e.ReceiverName == ReceiverName).FirstOrDefault();                        try                      {                          System.Diagnostics.Trace.WriteLine("Removing ItemAdded receiver at "                                 + rer.ReceiverUrl);                            //This will fail when deploying via F5, but works                          //when deployed to production                          rer.DeleteObject();                          clientContext.ExecuteQuery();                        }                      catch (Exception oops)                      {                          System.Diagnostics.Trace.WriteLine(oops.Message);                      }                    }              }          }         private void HandleAppInstalled(SPRemoteEventProperties properties)          {              using (ClientContext clientContext =                   TokenHelper.CreateAppEventClientContext(properties, false))              {                  if (clientContext != null)                  {                      List myList = clientContext.Web.Lists.GetByTitle(ListName);                      clientContext.Load(myList, p => p.EventReceivers);                      clientContext.ExecuteQuery();                        bool rerExists = false;                        foreach (var rer in myList.EventReceivers)                      {                          if (rer.ReceiverName == ReceiverName)                         {                              rerExists = true;                              System.Diagnostics.Trace.WriteLine("Found existing ItemAdded receiver at "                                  + rer.ReceiverUrl);                          }                      }                        if (!rerExists)                      {                          EventReceiverDefinitionCreationInformation receiver =                               new EventReceiverDefinitionCreationInformation();                          receiver.EventType = EventReceiverType.ItemAdded;                           //Get WCF URL where this message was handled                          OperationContext op = OperationContext.Current;                         Message msg = op.RequestContext.RequestMessage;                            receiver.ReceiverUrl = msg.Headers.To.ToString();                            receiver.ReceiverName = ReceiverName;                          receiver.Synchronization = EventReceiverSynchronization.Synchronous;                         myList.EventReceivers.Add(receiver);                            clientContext.ExecuteQuery();                            System.Diagnostics.Trace.WriteLine("Added ItemAdded receiver at "                                  + msg.Headers.To.ToString());                      }                  }              }          }         private void HandleItemAdded(SPRemoteEventProperties properties)          {              using (ClientContext clientContext =                   TokenHelper.CreateRemoteEventReceiverClientContext(properties))              {                  if (clientContext != null)                  {                      try                      {                          List photos = clientContext.Web.Lists.GetById(                                properties.ItemEventProperties.ListId);                          ListItem item = photos.GetItemById(                               properties.ItemEventProperties.ListItemId);                          clientContext.Load(item);                          clientContext.ExecuteQuery();                            item["Title"] += "\nUpdated by RER " +                                 System.DateTime.Now.ToLongTimeString();                          item.Update();                          clientContext.ExecuteQuery();                      }                      catch (Exception oops)                      {                          System.Diagnostics.Trace.WriteLine(oops.Message);                      }                  }                }            }          /// <summary>         /// This method is a required placeholder, but is not used by app events.         /// </summary>         /// <param name="properties">Unused.</param>         public void ProcessOneWayEvent(SPRemoteEventProperties properties)         {             throw new NotImplementedException();         }      } 

So can anyone advice why i am getting Null for the ClientContext ? and why the project will stop running?

ClientContext showing data as undefined

I had some code similar to this one for getting data from property bag.

However, I am getting some error that my variables are undefined. Even site and web are shown as undefined.

What could be the issue?

P.S: My variables usrname and psword are defined globally.

My code is below:

function getPropertyValues(){     var curSite = getCurrentSite();     var context = new SP.ClientContext.get_current();     var web = context.get_web();     var propertyBag = web.get_allProperties();      context.load(propertyBag );     context.executeQueryAsync(Function.createDelegate(this, this.getWebPropertiesSucceeded), Function.createDelegate(this, this.getWebPropertiesFailed)); }  function getWebPropertiesSucceeded() {     usrname = propertyBag.get_fieldValues()["ClientId"];     psword = propertyBag.get_fieldValues()["ClientSecret"]; }  function getWebPropertiesFailed(args, sender) {         //handle errors here   } 

ClientContext giving 403 Forbidden error

I am hosting my site in Azure

Azure and Office 365 have same account detail. But when I am using the following code it’s giving 403 error.

Also while accessing Azure site I already logged in Office 365 then also not able to take ClientContext. As I am aware i’ts SSO by Azure & Office 365.

 try  {      var siteUrl = "https://Office365Site";      using (var clientContext = new ClientContext(siteUrl))      {          clientContext.Load(clientContext.Web, web => web.Title);          clientContext.ExecuteQuery();          Response.Write(clientContext.Web.Title);       }  }  catch (Exception ex)  {      Response.Write(ex.Message);  } 

Please help in this issue.

Uploading files to sharepoint with clientContext giving Error

I am trying to upload documents to a specified sharepoint location but I am getting the error System.Net.WebException: ‘The remote server returned an error: (400) Bad Request.’

I believe this has something to do with the validation but not 100% on this. Below is my code and the error is returned at the ctx.ExecuteQuery();.

public static void sharepointUpload()         {             String filePath = @"C:\temp\test.pdf";             String siteUrl = "https://<myCompany>.sharepoint.com/";             String documentLibraryName = "PayPoint";             string fileName = filePath.Substring(filePath.LastIndexOf("\") + 1);              string userName = "firstname.surname@companyName.co.uk";             string password = "password";              SecureString securePassword = new SecureString();             foreach (char ch in password.ToCharArray())                 securePassword.AppendChar(ch);             SharePointOnlineCredentials credentials =                     new SharePointOnlineCredentials(userName, securePassword);              using (ClientContext ctx = new ClientContext(siteUrl))             {                 FileCreationInformation fcInfo = new FileCreationInformation();                 fcInfo.Url = fileName;                 fcInfo.Overwrite = true;                 fcInfo.Content = File.ReadAllBytes(filePath);                  ctx.Credentials = credentials;                 Web myWeb = ctx.Web;                 List myLibrary = myWeb.Lists.GetByTitle(documentLibraryName);                 myLibrary.RootFolder.Files.Add(fcInfo);                 ctx.Load(myWeb, w => w.Title);                 ctx.ExecuteQuery();                 Console.WriteLine(myWeb.Title);              }             Console.WriteLine("Succesful Upload");         } 

Should I use one or multiple ClientContext to update a very large List?

I need to update a large SharePoint List, about 10,000 items or more. Each ListItem has 4 columns to be updated. I don’t know what the best approach for this scenario is:

  1. Use 1 ClientContext, fetch ListItemCollection in batch of n rows, loop through each ListItem and update its columns before the next batch. Or
  2. Fetch a list of ListItemCollectionPosition in batch of n rows, loop through each ListItemCollectionPosition, create a new ClientContext, fetch ListItemCollection and then update.

Method 1

using (ClientContext ctx = new ClientContext(url)) {    ctx.Credentials = new SharePointOnlineCredentials(username,password);    List list = ctx.Web.Lists.GetByTitle("mylist");    ctx.Load(list);    ctx.ExecuteQuery();    ListItemCollectionPosition pos = null;    CamlQuery camlQuery = new CamlQuery    {        ViewXml = "<View Scope='Recursive'><RowLimit>100</RowLimit></View>"    };    do               {         if (pos != null)         {             camlQuery.ListItemCollectionPosition = pos;         }         ListItemCollection listItemCollection = list.GetItems(camlQuery);         ctx.Load(listItemCollection);         ctx.ExecuteQuery();         pos = listItemCollection.ListItemCollectionPosition;         foreach(ListItem item in listItemCollection)         {             item["col1"] = "abc";             item["col2"] = "def";             item["col3"] = "ghi";             item["col4"] = "jkl";             item.Update();         }         ctx.ExecuteQuery();     } while (pos != null); } 

Method 2

private void UpdateList() {    using (ClientContext ctx = new ClientContext(url))    {        ctx.Credentials = new SharePointOnlineCredentials(username,password);        List list = ctx.Web.Lists.GetByTitle("mylist");        ctx.Load(list);        ctx.ExecuteQuery();        ListItemCollectionPosition pos = null;        CamlQuery camlQuery = new CamlQuery        {            ViewXml = "<View Scope='Recursive'><RowLimit>100</RowLimit></View>"        };        List<ListItemCollectionPosition> positions = new List<ListItemCollectionPosition>();        do                   {            if (pos != null)            {                camlQuery.ListItemCollectionPosition = pos;            }            ListItemCollection listItemCollection = list.GetItems(camlQuery);            ctx.Load(listItemCollection);            ctx.ExecuteQuery();            pos = listItemCollection.ListItemCollectionPosition;            positions.Add(pos);                    } while (pos != null);        List<Task> tasks = new List<Task>();        foreach(var position in positions)        {            tasks.Add(UpdateItem(position));        }        Task.WaitAll(tasks.ToArray());     } } private Task UpdateItem(ListItemCollectionPosition pos) {    using (ClientContext ctx = new ClientContext(url))    {       ctx.Credentials = new SharePointOnlineCredentials(username,password);       List list = ctx.Web.Lists.GetByTitle("mylist");       ctx.Load(list);       ctx.ExecuteQuery();       CamlQuery camlQuery = new CamlQuery       {           ViewXml = "<View Scope='Recursive'><RowLimit>100</RowLimit></View>"       };       camlQuery.ListItemCollectionPosition = pos;       ListItemCollection listItemCollection = list.GetItems(camlQuery);       ctx.Load(listItemCollection);       ctx.ExecuteQuery();       foreach(ListItem item in listItemCollection)       {            item["col1"] = "abc";            item["col2"] = "def";            item["col3"] = "ghi";            item["col4"] = "jkl";            item.Update();       }       return ctx.ExecuteQueryAsync();     } } 

Is there a way to get CSOM ClientContext by having cookies and a Form Digest?

I have been trying to do an interesting proof-of-concept/experiment

  1. Get SharePoint user’s cookies from the browser
  2. Pass these cookies to an Azure Function
  3. By having cookies only – determine who the user is (+)
  4. Run GET/POST REST queries using user’s permissions (+)
  5. Run C#/CSOM code using user’s permissions (-)

This might be a very nice approach that works very well without the need for some nasty adal.js+iframe solutions that only work with Graph API and don’t work with Azure functions.

So, basically, I’m stuck with the last task #5. I have cookies and I have FormDigest, but I don’t know how to get CSOM ClientContext using this information. Is it even possible? Can someone, please help me with it? I will be really obliged for any tips.

I’m including a working code below. You can insert your own cookies there to try it out.

class Program {     static void Main(string[] args)     {         AsyncMain(args);         Console.ReadKey(false);     }      static async void AsyncMain(string[] args)     {         string baseurl = "https://contoso.sharepoint.com";         string rtFa = "REUSED_RtFA_Cookie";         string fedAuth = "REUSED_fedAUTH_COOKIE";          var digest = await GetDigest(baseurl, rtFa, fedAuth);          var baseAddress = new Uri(baseurl);         var cookieContainer = new CookieContainer();         using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer })         using (var client = new HttpClient(handler) { BaseAddress = baseAddress })         {             client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));             client.DefaultRequestHeaders.Add("X-RequestDigest", digest);              cookieContainer.Add(baseAddress, new Cookie("rtFa", rtFa));             cookieContainer.Add(baseAddress, new Cookie("FedAuth", fedAuth));              StringContent bodyContent = new StringContent("{\"__metadata\":{\"type\":\"SP.Data.ArtefactsListItem\"},\"Title\":\"NEW VALUE2\"}");             bodyContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json;odata=verbose");             var result = client.PostAsync("/_api/web/Lists/getByTitle('Artefacts')/items", bodyContent).Result;             var contents = await result.Content.ReadAsStringAsync();             result.EnsureSuccessStatusCode();             Console.WriteLine("SharePoint List Item Created using REST");         }          // TODO: Awesome! We can do REST calls using user's cookies, but it's much easier if we could somehow do it using CSOM. How do we get ClientContext from cookies and a Form Digest?         using (var context = new ClientContext(baseurl))         {             // TODO: I want get SPContext having user's cookies and Form Digest:             context.Credentials = new SharePointOnlineCredentials("", new System.Security.SecureString());             context.Load(context.Web, web => web.Title);             context.ExecuteQuery();             Console.WriteLine("Your site title is: " + context.Web.Title);         }     }      static async Task<string> GetDigest(string baseUrl, string rtFa, string FedAuth)     {         var baseAddress = new Uri(baseUrl);         var cookieContainer = new CookieContainer();         using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer })         using (var client = new HttpClient(handler) { BaseAddress = baseAddress })         {             client.DefaultRequestHeaders.Add("Accept", "application/json; odata=verbose");             cookieContainer.Add(baseAddress, new Cookie("rtFa", rtFa));             cookieContainer.Add(baseAddress, new Cookie("FedAuth", FedAuth));              var bodyContent = new StringContent("", Encoding.UTF8, "application/json");             var result = client.PostAsync(baseUrl+ "/_api/contextinfo", bodyContent).Result;             var contents = await result.Content.ReadAsStringAsync();               result.EnsureSuccessStatusCode();             dynamic response = JsonConvert.DeserializeObject(contents);             dynamic d = response.d;             string digest = d.GetContextWebInformation.FormDigestValue;              return digest;         }     } }