Getting a List of Folders (WebDAV)

Topic Last Modified: 2006-06-12

This topic demonstrates how to use the SEARCH Method to get a list of folders within a folder using a hierarchical search. For more information about hierarchical searches, see Search Scope.

See Constructing Exchange Store HTTP URLs and Authentication and Security Using WebDAV for more information.

This topic contains Microsoft® Visual Basic® Scripting Edition (VBScript), Microsoft Visual C++®, Microsoft C#, and Visual Basic .NET code examples.

The format of the SEARCH Method request is as follows:

SEARCH /vroot/folder/ HTTP/1.1
Content-Type: text/xml
Host: www.example.com

<?xml version="1.0"?>
<D:searchrequest xmlns:D = "DAV:">
   <D:sql>
   SELECT "DAV:href"
   FROM SCOPE('hierarchical traversal of "/vroot/folder/"')
   </D:sql>
</D:searchrequest>

Example

VBScript

The following example uses the SEARCH Method to perform a hierarchical search and get a list of all folders in TestStoreFolder.

Example

Option Explicit

' Variables.
dim req
dim strURL
dim strQuery

' The URL of the Exchange store folder to query.
strURL = "https://Server/TestStore/TestStoreFolder/"

' Build the query for a hierarchical search.
strQuery = "<?xml version=""1.0""?><D:searchrequest xmlns:D = ""DAV:"" >"
strQuery = strQuery & "<D:sql>SELECT ""DAV:href"" FROM scope('hierarchical traversal of """
strQuery = strQuery & strURL & """')</D:sql></D:searchrequest>"

' Create the XMLHTTP object.
set req = createobject("microsoft.xmlhttp")

' Specify the SEARCH method, the URL, that the request will be sent synchronously,
' the user name, and the password.
req.open "SEARCH", strURL, false, "Domain\Username", "!Password"

' Set the Content-Type header to "text/xml".
req.setrequestheader "Content-Type", "text/xml"

' Send the SEARCH request.
req.send strQuery

' An error occurred on the server.
If req.status >= 500 Then
   wscript.echo "Status: " & req.status
   wscript.echo "Status text: An error occurred on the server."

' Success. Display the status, status text, and folders found.
ElseIf req.status = 207 Then

   ' Variables.
   dim oResponseDoc
   dim oNodeList
   dim oNode

   ' Display request status and status text.
   wscript.echo "Status: " & req.status
   wscript.echo "Status text:  " & req.statustext

   ' Get the XML response body.
   set oResponseDoc = req.responseXML

   ' Build a list of the DAV:href XML nodes, corresponding to the folders
   ' returned in the search request. The DAV: namespace is typically
   ' assigned the a: prefix in the XML response body.
   set oNodeList = oResponseDoc.getElementsByTagName("a:href")

   ' Display the number of folders found.
   wscript.echo oNodeList.length & " Folders:"

   ' List the folders found.
   for each oNode in oNodeList
      wscript.echo oNode.Text

Else
   ' Display the status, status text, and response text.
   wscript.echo "Status: " & req.status
   wscript.echo "Status text: " & req.statustext
   wscript.echo "Response text: " & req.responsetext

End If

C++

The following example uses the SEARCH Method to perform a hierarchical search and get a list of all folders in TestStoreFolder.

Example

#include <stdio.h>
#include <iostream.h>

// If necessary, change the file path if your msxml.dll file is
// in a different location.

#import "c:\windows\system32\msxml.dll"

// To use MSXML 4.0, import the dll msxml4.dll instead of msxml.dll as follows:
// #import "c:\windows\system32\msxml4.dll"
// using namespace MSXML2;

using namespace MSXML;

int main(int argc, char* argv[])
{
   CoInitialize(NULL);

   // Variables.
   MSXML::IXMLHttpRequestPtr pXMLHttpReq=NULL;
   bstr_t sUrl = "https://Server/public/TestFolder1/";
   bstr_t sMethod = "SEARCH";
   _variant_t vUser = L"Domain\\Username";
   _variant_t vPassword = L"!Password";
   _variant_t vAsync = (bool)FALSE;
   long lStatus = 0;
   BSTR bstrResp;
   BSTR bstrResponseText;
   HRESULT hr;
   bstr_t sQuery = "";

   // Create an instance of the request object.
   hr = pXMLHttpReq.CreateInstance(__uuidof(XMLHTTPRequest));

   // If you are using MSXML 4.0, use the following to initialize pXMLHttpReq:
   // IXMLHTTPRequestPtr pXMLHttpReq= NULL;
   // HRESULT hr=pXMLHttpReq.CreateInstance("Msxml2.XMLHTTP.4.0");

   // Check the status of pointer creation.
   if (S_OK != hr)
   {
      cout << "Creation of XMLHTTPRequest failed." << endl;
      return 1;
   }

   try
   {
      // Open the XMLHTTPRequest object with the SEARCH method and
      // specify that it will be sent asynchronously.
      pXMLHttpReq->open(sMethod,
                        sUrl,
                        vAsync,
                        vUser,
                        vPassword);

      // Set the Content-Type header.
      pXMLHttpReq->setRequestHeader((bstr_t)"Content-Type", (bstr_t)"text/xml");

      // Build the query for a hierarchical search.
      sQuery = "<?xml version=\"1.0\"?><D:searchrequest xmlns:D = \"DAV:\" >";
      sQuery += "<D:sql>SELECT \"DAV:href\" FROM scope('hierarchical traversal of \"";
      sQuery += sUrl + "\"')</D:sql></D:searchrequest>";

      // Send the SEARCH method request.
      pXMLHttpReq->send(sQuery);

      // Get the response status.
      pXMLHttpReq->get_status(&lStatus);

      // An error occurred on the server.
      if(lStatus >= 500)
      {
         cout << "Status: " << lStatus << endl
              << "Status text: An error occurred on the server."
              << endl;
      }

      // The method request was successful.
      else if (lStatus == 207)
      {
          // Variables.
          MSXML::IXMLDOMDocumentPtr pDOMDoc = NULL;
          MSXML::IXMLDOMNodeListPtr pDOMNodeList = NULL;
          MSXML::IXMLDOMNodePtr pDOMNode = NULL;
          BSTR bstrText;

          // Create an instance of the DOM Document.
          HRESULT hr = pDOMDoc.CreateInstance(__uuidof(DOMDocument));

          // Check the status of pointer creation.
          if(FAILED(hr))
             cout<<"Creation of DOMDocument failed."<<endl;

          // Get the method response XML text.
          pXMLHttpReq->get_responseText(&bstrText);

          // Load the XML document with the response text.
          pDOMDoc->loadXML(bstrText);

          // Build a list of the DAV:href XML nodes, corresponding to the folders
          // returned in the search request. The DAV: namespace is typically
          // assigned the a: prefix in the XML response body.
          pDOMNodeList = pDOMDoc->getElementsByTagName((bstr_t)"a:href");

          // Display the number of folders found.
          cout << "Folders: " << pDOMNodeList->length
               << endl;

          // List the folders found.
          for(int i=0; i<pDOMNodeList->length;i++)
          {
             pDOMNode = pDOMNodeList->nextNode();
             cout<<pDOMNode->text<<endl;
          }
      }
      else
      {
         // Display the response status.
         cout << "Status: " << lStatus << endl;

         // Display the response status text.
         pXMLHttpReq->get_statusText(&bstrResp);
         cout << "Status text: " << (char*)(bstr_t)bstrResp << endl;

         // Display the response text.
         pXMLHttpReq->get_responseText(&bstrResponseText);
         cout << "Response text: " << (char*)(bstr_t)bstrResponseText << endl;
      }
   }
   catch(_com_error &e)
   {
      // Display the error information.
      cout << "Error code: " << (char*)e.Error() << endl
           << "Error message: " << (char*)e.ErrorMessage()
           <<endl;

      return 1;
   }

   CoUninitialize();

   return 0;
}

C#

The following example uses the SEARCH Method to perform a hierarchical search and get a list of all folders in TestStoreFolder.

Example

using System;
using System.Net;
using System.IO;
using System.Text;
using System.Xml;

namespace ExchangeSDK.Snippets.CSharp
{
   class GettingListOfFoldersWebDAV
   {
      [STAThread]
      static void Main(string[] args)
      {
         // Variables.
         System.Net.HttpWebRequest Request;
         System.Net.WebResponse Response;
         System.Net.CredentialCache MyCredentialCache;
         string strRootURI = "https://server/TestStore/TestStoreFolder/";
         string strUserName = "UserName";
         string strPassword = "!Password";
         string strDomain = "Domain";
         string strQuery ="";
         byte[] bytes = null;
         System.IO.Stream RequestStream = null;
         System.IO.Stream ResponseStream = null;
         System.Xml.XmlTextReader XmlReader = null;

         try
         {
            // Build the SQL query.
            strQuery = "<?xml version=\"1.0\"?><D:searchrequest xmlns:D = \"DAV:\" >";
            strQuery += "<D:sql>SELECT \"DAV:href\" FROM scope('hierarchical traversal of \"";
            strQuery += strRootURI + "\"')</D:sql></D:searchrequest>";

            // Create a new CredentialCache object and fill it with the network
            // credentials required to access the server.
            MyCredentialCache = new System.Net.CredentialCache();
            MyCredentialCache.Add( new System.Uri(strRootURI),
               "NTLM",
               new System.Net.NetworkCredential(strUserName, strPassword, strDomain)
               );

            // Create the HttpWebRequest object.
            Request = (System.Net.HttpWebRequest)HttpWebRequest.Create(strRootURI);

            // Add the network credentials to the request.
            Request.Credentials = MyCredentialCache;

            // Specify the method.
            Request.Method = "SEARCH";

            // Encode the body using UTF-8.
            bytes = Encoding.UTF8.GetBytes((string)strQuery);

            // Set the content header length.  This must be
            // done before writing data to the request stream.
            Request.ContentLength = bytes.Length;

            // Get a reference to the request stream.
            RequestStream = Request.GetRequestStream();

            // Write the SQL query to the request stream.
            RequestStream.Write(bytes, 0, bytes.Length);

            // Close the Stream object to release the connection
            // for further use.
            RequestStream.Close();

            // Set the content type header.
            Request.ContentType = "text/xml";

            // Send the SEARCH method request and get the
            // response from the server.
            Response = (HttpWebResponse)Request.GetResponse();

            // Get the XML response stream.
            ResponseStream = Response.GetResponseStream();

            // Create the XmlTextReader object from the XML
            // response stream.
            XmlReader = new XmlTextReader(ResponseStream);

            // Read through the XML response, node by node.
            while(XmlReader.Read())
            {
               // Look for the opening DAV:href node.  The DAV: namespace is
               //typically assigned the a: prefix in the XML response body.
               if(XmlReader.Name == "a:href")
               {
                  // Advance the reader to the text node.
                  XmlReader.Read();

                  // Display the value of the DAV:href text node.
                  Console.WriteLine("Value: " + XmlReader.Value);
                  Console.WriteLine("");

                  //Advance the reader to the closing DAV:href node.
                  XmlReader.Read();
               }
            }

            // Clean up.
            XmlReader.Close();
            ResponseStream.Close();
            Response.Close();

         }
         catch(Exception ex)
         {
            // Catch any exceptions. Any error codes from the SEARCH
            // method request on the server will be caught here, also.
            Console.WriteLine(ex.Message);
         }
      }
   }
}

Visual Basic .NET

The following example uses the SEARCH Method to perform a hierarchical search and get a list of all folders in TestStoreFolder.

Example

Option Explicit On
Option Strict On

Module Module1

Sub Main()

   ' Variables
   Dim Request As System.Net.HttpWebRequest
   Dim Response As System.Net.HttpWebResponse
   Dim MyCredentialCache As System.Net.CredentialCache
   Dim strPassword As String
   Dim strDomain As String
   Dim strUserName As String
   Dim strRootURI As String
   Dim strQuery As String
   Dim bytes() As Byte
   Dim RequestStream As System.IO.Stream
   Dim ResponseStream As System.IO.Stream
   Dim XmlReader As System.Xml.XmlTextReader

   Try
      ' Initialize variables.
      strUserName = "UserName"
      strPassword = "!Password"
      strDomain = "Domain"
      strRootURI = "https://server/TestStore/TestStoreFolder/"

      ' Build the SQL query.
      strQuery = "<?xml version=""1.0""?>" & _
                 "<D:searchrequest xmlns:D = ""DAV:"" >" & _
                 "<D:sql>SELECT ""dav:href"" FROM scope('hierarchical traversal of """ & _
                 strRootURI & """ ')</D:sql></D:searchrequest>"

      ' Create a new CredentialCache object and fill it with the network
      ' credentials required to access the server.
      MyCredentialCache = New System.Net.CredentialCache
      MyCredentialCache.Add(New System.Uri(strRootURI), _
          "NTLM", _
          New System.Net.NetworkCredential(strUserName, strPassword, strDomain) _
          )

      ' Create the SEARCH HttpWebRequest object.
      Request = CType(System.Net.WebRequest.Create(strRootURI), _
                      System.Net.HttpWebRequest)

      ' Add the network credentials to the request.
      Request.Credentials = MyCredentialCache

      ' Specify the SEARCH method.
      Request.Method = "SEARCH"

      ' Encode the body using UTF-8.
      bytes = System.Text.Encoding.UTF8.GetBytes(strQuery)

      ' Set the content header length.  This must be
      ' done before writing data to the request stream.
      Request.ContentLength = bytes.Length

      ' Get a reference to the request stream.
      RequestStream = Request.GetRequestStream()

      ' Write the message body to the request stream.
      RequestStream.Write(bytes, 0, bytes.Length)

      ' Close the Stream object to release the connection
      ' for further use.
      RequestStream.Close()

      ' Set the Content Type header.
      Request.ContentType = "text/xml"

      ' Send the SEARCH method request and get the
      ' response from the server.
      Response = CType(Request.GetResponse(), System.Net.HttpWebResponse)

      ' Get the XML response stream.
      ResponseStream = Response.GetResponseStream()

      ' Create the XmlTextReader object from the XML
      ' response stream.
      XmlReader = New System.Xml.XmlTextReader(ResponseStream)

      ' Read through the XML response, node by node.
      While (XmlReader.Read())

          ' Look for the opening DAV:href node.  The DAV: namespace is
          ' typically assigned the a: prefix in the XML response body.
          If XmlReader.Name = "a:href" Then

              ' Advance the reader to the text node.
              XmlReader.Read()

              ' Display the value of the DAV:href text node.
              Console.WriteLine("Value: " + XmlReader.Value)
              Console.WriteLine("")

              ' Advance the reader to the closing DAV:href node.
              XmlReader.Read()
          End If
      End While

   ' Clean up.
   XmlReader.Close()
   ResponseStream.Close()
   Response.Close()

   Catch ex As Exception

      ' Catch any exceptions. Any error codes from the
      ' SEARCH method requests on the server will be caught
      ' here, also.
      Console.WriteLine(ex.Message)

   End Try

End Sub

End Module