As a cutting-edge programmer, you might be wondering how you call WebDAV from .NET. The .NET Framework includes the HTTPWebRequest and HTTPWebResponse classes, which allow you to make WebDAV calls to the server. The easiest way to learn how to use these classes is to see a sample application. Figure 16-10 shows a WebDAV client sample application. This application shows how to do PROPPATCH , PROPFIND , and searches using these classes.
The following is the code from the sample application:
Imports System.Net Imports System.IO Imports System.Xml Public Class Form1 Inherits System.Windows.Forms.Form Dim iCurStep = 1 Dim strURL As String = "" Dim bFailed As Boolean Dim responsestring As String = "" 'This sample shows how to leverage the httpwebrequest 'and httpwebresponse objects against Exchange or SPS '5 things are shown '1: Creating an item '2: Using a proppatch '3: Using a propfind '4: Performing a search '5: Loading that search into a dataset #Region " Windows Form Designer generated code " . . . #End Region Private Sub txtPerformStep_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles cmdPerformStep.Click 'Check the current step If iCurStep = 1 Then 'Check the URL of the folder If txtURL.Text = "" Then MsgBox("You must enter a valid URL!", _ MsgBoxStyle.Exclamation + MsgBoxStyle.OKOnly) Exit Sub Else 'perform the step: Create the item Try If Microsoft.VisualBasic.Right(txtURL.Text, 1) = "/" Then strURL = txtURL.Text Else strURL = txtURL.Text & "/" End If lblRequest.Text = "PUT " & strURL bFailed = False bFailed = CallWebRequest(strURL & "newitem.eml", "PUT", _ "message/rfc822", "", "Subject: Test") If bFailed Then MsgBox("Web request failed!") Exit Sub End If iCurStep = 2 lblCurrentStep.Text = "Step 2: Perform a Proppatch" cmdPerformStep.Text = "Perform Step 2" Catch MsgBox("Error on the 1st step. Error#:" & Err.Number _ & " Description: " & Err.Description) Exit Sub End Try End If ElseIf iCurStep = 2 Then Try Dim strXML As String strXML = "<?xml version=""1.0""?>" _ & "<D:propertyupdate xmlns:D=""DAV:"" " _ & "xmlns:M=""urn:schemas:httpmail:"">" strXML += "<D:set><D:prop><M:subject>New Message " _ & "Subject</M:subject><M:textdescription>" _ & "This is the body of the message</M:textdescription>" strXML += "</D:prop></D:set></D:propertyupdate>" lblRequest.Text = strXML bFailed = False bFailed = CallWebRequest(strURL & "newitem.eml", _ "PROPPATCH", "text/xml", "", strXML) If bFailed Then MsgBox("Web request failed!") Exit Sub End If iCurStep = 3 lblCurrentStep.Text = "Step 3: Perform Propfind" cmdPerformStep.Text = "Perform Step " & iCurStep Catch MsgBox("Error on the 2nd step. Error#:" & Err.Number _ & " Description: " & Err.Description) End Try ElseIf iCurStep = 3 Then Try Dim strXML As String strXML = "<?xml version=""1.0""?>" _ & "<D:propfind xmlns:D=""DAV:"">" strXML += "<D:prop><D:displayname/>" _ & "<D:getlastmodified/><D:creationdate/>" strXML += "</D:prop></D:propfind>" lblRequest.Text = strXML bFailed = False bFailed = CallWebRequest(strURL & "newitem.eml", "PROPFIND", _ "text/xml", "1,noroot", strXML) If bFailed Then MsgBox("Web request failed!") Exit Sub End If iCurStep = 4 lblCurrentStep.Text = "Step 4: Perform a search" cmdPerformStep.Text = "Perform Step " & iCurStep Catch MsgBox("Error on the 3rd step. Error#:" & Err.Number _ & " Description: " & Err.Description) End Try ElseIf iCurStep = 4 Then Try Dim strXML As String Dim strSQL As String = "SELECT ""DAV:href"", " strSQL += """urn:schemas:httpmail:subject""" strSQL += "FROM SCOPE('SHALLOW TRAVERSAL OF """ & strURL strSQL += """') WHERE ((""urn:schemas:httpmail:subject"" = '" strSQL += "New Message Subject'))" strXML = "<?xml version=""1.0""?>" strXML += "<d:searchrequest xmlns:d=""DAV:"">" strXML += "<d:sql>" & strSQL & "</d:sql>" strXML += "</d:searchrequest>" lblRequest.Text = strXML bFailed = False bFailed = CallWebRequest(strURL, "SEARCH", "text/xml", _ "1", strXML) If bFailed Then MsgBox("Web request failed!") Exit Sub End If iCurStep = 5 lblCurrentStep.Text = "Step 5: Load a search " _ & "into a Dataset object" cmdPerformStep.Text = "Perform Step " & iCurStep Catch MsgBox("Error on the 4th step. Error#:" & Err.Number _ & " Description: " & Err.Description) End Try ElseIf iCurStep = 5 Then Try Dim strXML As String Dim strSQL As String = "SELECT ""DAV:href"", " strSQL += """urn:schemas:httpmail:subject"", " strSQL += """urn:schemas:httpmail:textdescription""" strSQL += "FROM SCOPE('SHALLOW TRAVERSAL OF """ & strURL strSQL += """') WHERE ((""urn:schemas:httpmail:subject"" = '" strSQL += "New Message Subject'))" strXML = "<?xml version=""1.0""?>" strXML += "<d:searchrequest xmlns:d=""DAV:"">" strXML += "<d:sql>" & strSQL & "</d:sql>" strXML += "</d:searchrequest>" lblRequest.Text = strXML bFailed = False bFailed = CallWebRequest(strURL, "SEARCH", "text/xml", _ "1", strXML) If bFailed Then MsgBox("Web request failed!") Exit Sub End If Dim output As Byte() = System.Text.Encoding.GetEncoding( _ 1252).GetBytes(responsestring) 'Load the XmlDocument object with the results for parsing Dim outputStream As MemoryStream = New MemoryStream(output) Dim outputReader As XmlTextReader = _ New XmlTextReader(outputStream) Dim resultdoc As XmlDataDocument = New XmlDataDocument() resultdoc.DataSet.ReadXml(outputReader) Dim resultSet As New Data.DataSet() resultSet = resultdoc.DataSet DataGrid1.SetDataBinding(resultSet, "") Label7.Text = "Dataset (Active)" lblCurrentStep.Text = "Completed." cmdPerformStep.Enabled = False Catch MsgBox("Error on the 5th step. Error#:" & Err.Number _ & " Description: " & Err.Description) End Try End If End Sub Public Function CallWebRequest(ByVal strURL, ByVal strMethod, _ ByVal strContentType, ByVal strDepthHeader, _ ByVal strXML) As Boolean Try Dim oHTTPRequest As HttpWebRequest = _ CType(WebRequest.Create(strURL), HttpWebRequest) oHTTPRequest.PreAuthenticate = True oHTTPRequest.Credentials = _ New NetworkCredential(txtUserName.Text, txtPassword.Text) oHTTPRequest.Method = strMethod oHTTPRequest.Headers.Add("Translate", "f") If strDepthHeader <> "" Then oHTTPRequest.Headers.Add("Depth", strDepthHeader) End If oHTTPRequest.ContentType = strContentType oHTTPRequest.ContentLength = strXML.Length Dim byteXML() As Byte = _ System.Text.Encoding.ASCII.GetBytes(strXML) Dim oStream As Stream = oHTTPRequest.GetRequestStream oStream.Write(byteXML, 0, byteXML.Length) oStream.Close() Dim oHTTPResponse As HttpWebResponse = oHTTPRequest.GetResponse() Dim oReader As StreamReader oReader = New StreamReader(oHTTPResponse.GetResponseStream, _ System.Text.Encoding.ASCII) txtResponse.Text = oReader.ReadToEnd responsestring = txtResponse.Text CallWebRequest = False Catch MsgBox("Error! Error#:" & Err.Number & " Description: " _ & Err.Description) CallWebRequest = True End Try End Function End Class
The first thing to notice in the code is that all the WebDAV commands are the same commands we used with the XMLHTTP component. You can make the same calls using the HTTPWebRequest component.
Next , notice that the meat of the code is contained in the CallWebRequest function. This is the function that takes the WebDAV command and sends it to the server. Let's step through this code and examine what it does.
The first section of the code creates a new HTTPWebRequest object that points at the URL passed to the function. We need to typecast the standard WebRequest object that is returned by the WebRequest Create method to an HTTPWebRequest object.
Next the code sets the PreAuthenticate property to True . This setting means that when we make our request to the server, .NET will include the WWW-Authenticate header and pass our credentials to the Web server. This frees the application from having to request the credentials from the user .
Next the code sets the credentials to the specified username and password to impersonate for the request. Immediately after that the code also sets the WebDAV method to use, such as PROPFIND or PROPPATCH . Then the code sets some headers, such as the Translate header and the Depth header. The code also sets the Content-Type and Content-Length headers.
The next section of code is very important. This is the section where we actually set the body of our request that we will send to the server. Note that the ContentLength property must be set before you call any of the code that follows that property. First the code loads the body of the request into a byte array. The reason for this is so we can load the byte array into the stream, which is returned by the GetRequestStream method on the HTTPWebRequest object. Then, to make our WebDAV call to the server, we need to call the Write method on the stream, passing in our byte array, the offset of which is zero in this case, and finally the number of bytes to write, which is the length of our byte array.
The next section of code uses the HTTPWebResponse to get the HTTP response back from the server. First, to get the response, the code calls the GetResponse method on the HTTPWebRequest object. Because the contents of the response are returned in an HTTPWebResponse object and that object requires us to use a stream to read that response, the code creates a new StreamReader object. Then the code reads the stream from the HTTPWebResponse into the StreamReader and uses the ReadToEnd method to write out the text of the response to the screen.
That is all you need to do to leverage WebDAV from your .NET applications. The other interesting part of the code is where the response is loaded into a dataset. This code is similar to the code we saw in the free/busy Web service consumer application in Chapter 14, so I won't cover the code here.