Freigeben über


Sending WebDAV Requests in .NET

Earlier today one of my coworkers, John Bocharov, asked me if I had ever done any WebDAV coding in .NET - specifically sending PUT and DELETE requests. I replied that I had, but it had been several months ago, and each time that I had written any WebDAV-related code samples it was for a specific purpose and not very exhaustive. Just the same, I promised John that if I found any of my old code samples I would send them to him. After a bit of searching through my archives I was able to find enough code snippets to throw together a quick sample for PUT and DELETE that John could use, but it made me start thinking about putting together a more complete sample by adding a few extra WebDAV methods, thereby creating a better example to keep around.

With that in mind, the code sample in this blog post shows how to send several of the most-common WebDAV requests using C# and common .NET libraries. There's a bit of intentional redundancies in each section of the sample - I did this because I was trying to make each section somewhat self-sufficient so you can copy and paste a little easier. I present the WebDAV methods the in the following order:

WebDAV Method Notes
PUT This section of the sample writes a string as a text file to the destination server as "foobar1.txt". Sending a raw string is only one way of writing data to the server, in a more common scenario you would probably open a file using a steam object and write it to the destination. One thing to note in this section of the sample is the addition of the "Overwrite" header, which specifies that the destination file can be overwritten.
COPY This section of the sample copies the file from "foobar1.txt" to "foobar2.txt", and uses the "Overwrite" header to specify that the destination file can be overwritten. One thing to note in this section of the sample is the addition of the "Destination" header, which obviously specifies the destination URL. The value for this header can be a relative path or an FQDN, but it may not be an FQDN to a different server.
MOVE This section of the sample moves the file from "foobar2.txt" to "foobar1.txt", thereby replacing the original uploaded file. As with the previous two sections of the sample, this section of the sample uses the "Overwrite" and "Destination" headers.
GET This section of the sample sends a WebDAV-specific form of the HTTP GET method to retrieve the source code for the destination URL. This is accomplished by sending the "Translate: F" header and value, which instructs IIS to send the source code instead of the processed URL. In this specific sample I am only using text files, but if the requests were for ASP.NET or PHP files you would need to specify the "Translate: F" header/value pair in order to retrieve the source code.
DELETE This section of the sample deletes the original file, thereby cleaning off all of the sample files from the destination server.
MKCOL This section of the sample creates a folder named "foobar3" on the destination server; as far as WebDAV on IIS is concerned, the MKCOL method is a lot like the old DOS MKDIR command.
DELETE This section of the sample deletes the folder from the destination server.

That wraps up the section descriptions, and with that taken care of - here is the code sample:

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

class WebDavTest
{
   static void Main(string[] args)
   {
      try
      {
         // Define the URLs.
         string szURL1 = @"https://localhost/foobar1.txt";
         string szURL2 = @"https://localhost/foobar2.txt";
         string szURL3 = @"https://localhost/foobar3";

         // Some sample text to put in text file.
         string szContent = String.Format(
            @"Date/Time: {0} {1}",
            DateTime.Now.ToShortDateString(),
            DateTime.Now.ToLongTimeString());

         // Define username and password strings.
         string szUsername = @"username";
         string szPassword = @"password";

         // --------------- PUT REQUEST --------------- //

         // Create an HTTP request for the URL.
         HttpWebRequest httpPutRequest =
            (HttpWebRequest)WebRequest.Create(szURL1);

         // Set up new credentials.
         httpPutRequest.Credentials =
            new NetworkCredential(szUsername, szPassword);

         // Pre-authenticate the request.
         httpPutRequest.PreAuthenticate = true;

         // Define the HTTP method.
         httpPutRequest.Method = @"PUT";

         // Specify that overwriting the destination is allowed.
         httpPutRequest.Headers.Add(@"Overwrite", @"T");

         // Specify the content length.
         httpPutRequest.ContentLength = szContent.Length;

         // Optional, but allows for larger files.
         httpPutRequest.SendChunked = true;

         // Retrieve the request stream.
         Stream requestStream =
            httpPutRequest.GetRequestStream();

         // Write the string to the destination as a text file.
         requestStream.Write(
            Encoding.UTF8.GetBytes((string)szContent),
            0, szContent.Length);

         // Close the request stream.
         requestStream.Close();

         // Retrieve the response.
         HttpWebResponse httpPutResponse =
            (HttpWebResponse)httpPutRequest.GetResponse();

         // Write the response status to the console.
         Console.WriteLine(@"PUT Response: {0}",
            httpPutResponse.StatusDescription);

         // --------------- COPY REQUEST --------------- //

         // Create an HTTP request for the URL.
         HttpWebRequest httpCopyRequest =
            (HttpWebRequest)WebRequest.Create(szURL1);

         // Set up new credentials.
         httpCopyRequest.Credentials =
            new NetworkCredential(szUsername, szPassword);

         // Pre-authenticate the request.
         httpCopyRequest.PreAuthenticate = true;

         // Define the HTTP method.
         httpCopyRequest.Method = @"COPY";

         // Specify the destination URL.
         httpCopyRequest.Headers.Add(@"Destination", szURL2);

         // Specify that overwriting the destination is allowed.
         httpCopyRequest.Headers.Add(@"Overwrite", @"T");

         // Retrieve the response.
         HttpWebResponse httpCopyResponse =
            (HttpWebResponse)httpCopyRequest.GetResponse();

         // Write the response status to the console.
         Console.WriteLine(@"COPY Response: {0}",
            httpCopyResponse.StatusDescription);

         // --------------- MOVE REQUEST --------------- //

         // Create an HTTP request for the URL.
         HttpWebRequest httpMoveRequest =
            (HttpWebRequest)WebRequest.Create(szURL2);

         // Set up new credentials.
         httpMoveRequest.Credentials =
            new NetworkCredential(szUsername, szPassword);

         // Pre-authenticate the request.
         httpMoveRequest.PreAuthenticate = true;

         // Define the HTTP method.
         httpMoveRequest.Method = @"MOVE";

         // Specify the destination URL.
         httpMoveRequest.Headers.Add(@"Destination", szURL1);

         // Specify that overwriting the destination is allowed.
         httpMoveRequest.Headers.Add(@"Overwrite", @"T");

         // Retrieve the response.
         HttpWebResponse httpMoveResponse =
            (HttpWebResponse)httpMoveRequest.GetResponse();

         // Write the response status to the console.
         Console.WriteLine(@"MOVE Response: {0}",
            httpMoveResponse.StatusDescription);

         // --------------- GET REQUEST --------------- //

         // Create an HTTP request for the URL.
         HttpWebRequest httpGetRequest =
            (HttpWebRequest)WebRequest.Create(szURL1);

         // Set up new credentials.
         httpGetRequest.Credentials =
            new NetworkCredential(szUsername, szPassword);

         // Pre-authenticate the request.
         httpGetRequest.PreAuthenticate = true;

         // Define the HTTP method.
         httpGetRequest.Method = @"GET";

         // Specify the request for source code.
         httpGetRequest.Headers.Add(@"Translate", "F");

         // Retrieve the response.
         HttpWebResponse httpGetResponse =
            (HttpWebResponse)httpGetRequest.GetResponse();

         // Retrieve the response stream.
         Stream responseStream =
            httpGetResponse.GetResponseStream();

         // Retrieve the response length.
         long responseLength =
            httpGetResponse.ContentLength;

         // Create a stream reader for the response.
         StreamReader streamReader =
            new StreamReader(responseStream, Encoding.UTF8);

         // Write the response status to the console.
         Console.WriteLine(
            @"GET Response: {0}",
            httpGetResponse.StatusDescription);
         Console.WriteLine(
            @"  Response Length: {0}",
            responseLength);
         Console.WriteLine(
            @"  Response Text: {0}",
            streamReader.ReadToEnd());

         // Close the response streams.
         streamReader.Close();
         responseStream.Close();

         // --------------- DELETE REQUEST --------------- //

         // Create an HTTP request for the URL.
         HttpWebRequest httpDeleteFileRequest =
            (HttpWebRequest)WebRequest.Create(szURL1);

         // Set up new credentials.
         httpDeleteFileRequest.Credentials =
            new NetworkCredential(szUsername, szPassword);

         // Pre-authenticate the request.
         httpDeleteFileRequest.PreAuthenticate = true;

         // Define the HTTP method.
         httpDeleteFileRequest.Method = @"DELETE";

         // Retrieve the response.
         HttpWebResponse httpDeleteFileResponse =
            (HttpWebResponse)httpDeleteFileRequest.GetResponse();

         // Write the response status to the console.
         Console.WriteLine(@"DELETE Response: {0}",
            httpDeleteFileResponse.StatusDescription);

         // --------------- MKCOL REQUEST --------------- //

         // Create an HTTP request for the URL.
         HttpWebRequest httpMkColRequest =
            (HttpWebRequest)WebRequest.Create(szURL3);

         // Set up new credentials.
         httpMkColRequest.Credentials =
            new NetworkCredential(szUsername, szPassword);

         // Pre-authenticate the request.
         httpMkColRequest.PreAuthenticate = true;

         // Define the HTTP method.
         httpMkColRequest.Method = @"MKCOL";

         // Retrieve the response.
         HttpWebResponse httpMkColResponse =
            (HttpWebResponse)httpMkColRequest.GetResponse();

         // Write the response status to the console.
         Console.WriteLine(@"MKCOL Response: {0}",
            httpMkColResponse.StatusDescription);

         // --------------- DELETE REQUEST --------------- //

         // Create an HTTP request for the URL.
         HttpWebRequest httpDeleteFolderRequest =
            (HttpWebRequest)WebRequest.Create(szURL3);

         // Set up new credentials.
         httpDeleteFolderRequest.Credentials =
            new NetworkCredential(szUsername, szPassword);
         
         // Pre-authenticate the request.
         httpDeleteFolderRequest.PreAuthenticate = true;

         // Define the HTTP method.
         httpDeleteFolderRequest.Method = @"DELETE";

         // Retrieve the response.
         HttpWebResponse httpDeleteFolderResponse =
            (HttpWebResponse)httpDeleteFolderRequest.GetResponse();

         // Write the response status to the console.
         Console.WriteLine(@"DELETE Response: {0}",
            httpDeleteFolderResponse.StatusDescription);

      }
      catch (Exception ex)
      {
         Console.WriteLine(ex.Message);
      }
   }
}

When you run the code sample, if there are no errors you should see something like the following output:

 PUT Response: CreatedCOPY Response: CreatedMOVE Response: No ContentGET Response: OK  Response Length: 30  Response Text: Date/Time: 2/9/2010 7:21:46 PMDELETE Response: OKMKCOL Response: CreatedDELETE Response: OKPress any key to continue . . .

Since the code sample cleans up after itself, you should not see any files or folders on the destination server when it has completed executing. To see the files and folders actually created and deleted on the destination server, you can step through the code in a debugger.

Closing Notes

I should point out that I did not include examples of the WebDAV PROPPATCH/PROPFIND and LOCK/UNLOCK methods in this sample because they require processing the XML responses, and that was way outside the scope of what I had originally wanted to do with this sample. I might write a follow-up blog later that shows how to use those methods, but I'm not making any promises. ;-]

I hope this helps.

Comments

  • Anonymous
    October 12, 2011
    would like to create a sample application using webdav protocol.I am new to Webdav. My requirement is as follows Store the word document in IIS server Create a client which will access the document I might have to write a class which would recide on server side for responding to requests sent by client. In other words the class on server side would be to respond to handle requests raised by webdav mini redirector. COuld you please suggest me how I could create. The reason for creating the application is whenever we try to access a document on a server using webdav protocol if get requests takes more than 50 seconds to respond to client ,the webdav miniredirector sends an unlock request even though the time out set on lock response is more than 60 minutes.Due to this unlock request the document opens in read -only mode and quits. Discussed with microsoft but microsoft wants a reproducable scenario hence have to create the application  with get request delay of 60 seconds such that the unlock request would be sent automatically. Kindly help this is an escalated issue ,not able to find any help on internet search

  • Anonymous
    October 27, 2011
    Hi Bhanu, I know that we aleady talked about this issue offline, but I thought that I'd share the information here for everyone else to see. The UNLOCK is caused by the SendReceiveTimeoutInSec registry setting for the WebDAV redirector. For more information on that setting, see the following walkthrough: learn.iis.net/.../using-the-webdav-redirector In addition, I wrote a user interface for updating the WebDAV redirector settings that is available at the following URL: blogs.msdn.com/.../how-to-create-an-html-application-to-configure-your-webdav-redirector-settings.aspx Thanks!

  • Anonymous
    June 07, 2012
    Will this work with IIS 7.5?

  • Anonymous
    June 08, 2012
    Hi Asim, Yes - this will work with IIS 7.5; actually, I wrote and tested this with IIS 7.5. ;-]

  • Anonymous
    February 01, 2014
    This is awesome! I just used your 'PUT' code to solve a requirement that involved sending a very large zipped file to a WebDAV share. I was able to get the recipient to accept split zip files but my earlier version of the code involved a PowerShell script using ADODB stream that would occasionally time out on files larger than 2MB. Using the HTTPWebRequest code above allowed me to increase the file size to 5MB (sending about 180 files over a period of an hour) with consistently successful transmissions. I don't know when or if I will need to interact with WebDAV again but I'm sure glad I stumbled upon your post. thanks again!