title: Work Backwards Through URL to Find the First Existing Folder
body: <p>We have written an API that helps internal users upload and download from SharePoint Online via Excel and other tools. The code is all in C# and we have a 'Browser' UI that allows users to navigate to sites/folder/files by host etc.<br />
  We've had some feedback that if a user supplies an invalid folder request, can we work backwords until we find the first valid child folder of the Documents root.<br />
  So, as an example, a user provides the URL:<br />
  <a href="https://example.sharepoint.com/sites/client_XXXXXX_Description/Documents/AdditionalDocuments/CalculationMaterials/CalculationLogging/Job99/" rel="nofollow noreferrer">https://example.sharepoint.com/sites/client_XXXXXX_Description/Documents/AdditionalDocuments/CalculationMaterials/CalculationLogging/Job99/</a><br />
  Where both CalculationLogging and Job99 doesn't exist. What I need to do is, starting at Job99, work backwards each level until I find a valid folder, i.e. <a href="https://example.sharepoint.com/sites/client_XXXXXX_Description/Documents/AdditionalDocuments/CalculationMaterials/" rel="nofollow noreferrer">https://example.sharepoint.com/sites/client_XXXXXX_Description/Documents/AdditionalDocuments/CalculationMaterials/</a><br />
  BUT if its get as far back as Documents, then stop, and tell user they have provided an invalid path.<br />
  Here's my code though it feels a bit 'clunky'!</p>
  <pre><code>                // Define new object
              var gc = new GraphClient();
              // Check to see if the item exists
              var exists = await gc.CheckRemoteItemExistsAsync(model.Url);
              // Based on the results of the request
              switch (exists)
              {
                  // The path is a valid file
                  case &quot;file&quot;:
                      // Store the actual filename from the path
                      model.FileName = model.Url.Substring(model.Url.LastIndexOf('/') + 1);
                      // remove the filename from the URL (as we don't use it)
                      model.Url = model.Url.Substring(0, model.Url.LastIndexOf('/') + 1);
                      break;
                  // The path is a valid folder
                  case &quot;folder&quot;:
                      // Append a trailing / if not present
                      if (!model.Url.EndsWith(&quot;/&quot;)) model.Url += &quot;/&quot;;
                      break;
                  case null:
                      // Store the first parent folder as we know the existing child doesn't exist
                      var subFolder = model.Url.Substring(0, model.Url.LastIndexOf('/') + 1);
                      var folderLoops = subFolder.Split('/').Length;
                      // ** Where the path starts with http, deduct 2 from the length **
                      if (subFolder.Split('/')[0].StartsWith(&quot;http&quot;))
                      {
                          folderLoops -= 2;
                      }
                      // loop through each folder until you find one that is valid
                      for (var i = folderLoops; i &gt; 1; i--)
                      {
                          // If the parent folder is Documents
                          if (subFolder.Split('/')[i] == &quot;Documents&quot;)
                          {
                              // Tell user path is invalid
                              MessageBox.Show(
                                  string.Format(Resources.PathDoesNotExistsWarningMessage, $&quot;{model.Url}&quot;),
                                  Resources.PathDoesNotExistsWarningMessageCaption,
                                  MessageBoxButtons.OK);
                              // exit the loop
                              break;
                          }
  
                          // Check to see if the item exists
                          exists = await gc.CheckRemoteItemExistsAsync(subFolder);
                          // Based on the results of the request
                          switch (exists)
                          {
                              // The path is a valid file
                              case &quot;file&quot;:
                              case &quot;folder&quot;:
                                  break;
                              case null:
                                  // Get the parent folder including the trailing /
                                  subFolder = subFolder.Substring(0,
                                      subFolder.Substring(0, subFolder.Length - 1).LastIndexOf('/') + 1);
                                  continue;
                          }
                      }
  
                      break;
              }
  </code></pre>
  <p>The ** comment (line 4) is to explain I'm deducting 2 as when the path starts with https://, the split function will return https as item 0, and an empty string as item 1.<br />
  FYI The function CheckRemoteItemExistsAsync is using Graph API to check whether the path contains a valid DriveItem or not.</p>