Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

.NET Data Access Class for Exchange 2000 Webstore

0.00/5 (No votes)
16 Aug 2005 15  
Assembly written in VB.NET that accesses Exchange 2000 Webstore data, using WEBDAV.

Important Update:

The XSLT files that were previously provided online at webservices.bus.oregonstate.edu are no longer going to be available. Instead you will need to download them and change the lines as described in the Updates section below. Please see the Updates section!

Introduction

The ExDAV assembly is a collection of classes that are useful for querying and authoring against a Microsoft Exchange 2000 webstore. This is accomplished within the classes by communicating with the store, using WebDAV. The classes wrap all the communications so that the programmer using the classes doesn't have to implement the WebDAV calls manually. The assembly provides the ability to do SQL like searches using the Exchange 2000 'SEARCH' verb, as well as the standard WebDAV verbs like 'PROPFIND'. Search results can be returned in raw XML form, as an XML.NET XML document, as ADO.NET DataSets, and, in the case of a 'PROPFIND', as a recursive object which is included in the assembly. In terms of authoring, the assembly provides the ability to write properties, create items and collections, copy, move, and delete.

Background

This object was created because of our need to access Exchange 2000 webstore data from our .NET applications. Our intent was to create a set of classes that would allow us to work with the Exchange data, without having to do any messy wrapping of COM components.

Using the code

To use the assembly, there are three classes that are the most important: ExSearcher, ExModifier and ExResponse. The ExSearcher class is used to query the Exchange Store and has two methods for doing this, Search and Find. The Search method takes a string parameter sWhere which is a SQL WHERE clause that is used to filter the results of the search. The request sent to the Exchange Store is done so in a SQL format (code snippets are in C#).

ExDAV.ExSearcher searcher = new 
        ExDav.ExSearcher("http://mystore.edu/myresource");
searcher.Depth = ExDAV.ExRequest.ExRequestDepths.AllChildrenWithRoot;
searcher.ExProps.Add("DAV:", "creationdate");
ExDAV.ExResponse resp = searcher.Search("WHERE \"DAV:isfolder\" = true");
...

I'll get to the ExResponse class in a minute.

Important Note: for both the ExSearcher and the ExModifier, properties which are to be retrieved or modified must be added to the ExProps collection which is a collection of ExProperty objects. Properties are specified using a URN, a Local Name, and in the case of an update, a Value. The code below shows how the DAV:creationdate property is set to be retrieved on our searcher (URN = 'DAV:', Local Name = 'creationdate'):

...
searcher.ExProps.Add("DAV:", "creationdate");
...

The Find method performs a similar function except with no SQL WHERE clause filter. The request sent to the Exchange Store is a typical 'PROPFIND' WebDAV call (here too we need to add the properties we are 'Finding', into the ExProps collection).

ExDAV.ExSearcher searcher = new 
        ExDav.ExSearcher("http://mystore.edu/myresource");
searcher.Depth = ExDAV.ExRequest.ExRequestDepths.AllChildrenWithRoot;
//Add the properties to look for

searcher.ExProps.Add("DAV:", "creationdate");
ExDAV.ExResponse resp = searcher.Find();
...

So now to get back to the ExResponse class. This class is how the response from the server is extracted. The ExResponse class has several methods for returning the results in different ways. The ResponseXML property can be used to retrieve the raw XML returned by the Exchange Store.

...
string sRawXML = resp.ResponseXML;
...

Other methods allow a response to be analyzed as a System.Xml.XmlDocument, or a System.Data.DataSet, or as an ExDAV.ExObject. (Important: the ExObject can only be used for the responses of the ExDAV.Searcher.Find() method.)

...
System.Data.DataSet ds = resp.GetDataSet("dsMyExDataSet", 
                                       "dsMyExTableName");
...

Tip: The ExResponse class' GetDatasetSchemaXMLReader method returns a System.IO.StringReader which contains the schema of the DataSet returned by the GetDataSet method. This allows the programmer to save the schema and even create strongly typed dataset schema files, to data bind controls to.

The ExModifier class is used to author against the Exchange Store. The authoring methods include: CreateNewItem, CreateFolder, CopyTo, MoveTo, Update, and Delete. These methods are pretty self explanatory.

ExDAV.ExModifier modifier = new 
         ExDav.ExModifier("http://mystore.edu/myitem.eml"); 
modifier.Depth = ExDAV.ExRequest.ExRequestDepths.NullDepth;
//set up the credential

modifier.Credential = new System.Net.NetworkCredential("myUserName", 
                                               "myPassword", "myDomain");
//add the property to update

modifier.ExProps.Add("DAV:", "displayname", "MyItemNewName");
ExDAV.ExResponse resp = modifier.Update(true, 
         ExDAV.ExModifier.ModifierFlags.AddIfNotExistsOverwriteIfExists);
...

The StatCode and StatDesc properties on the ExResponse object that is returned, can be used to analyze the success of the request.

For more information on how to use the assembly, see the comments in the source code and the demo project.

Under the covers

I had some requests to discuss the implementation of WebDAV within the assembly as well as our methods for retrieving the results, so for those interested here it goes. Both the ExSearcher and the ExModifier inherit from the ExRequest class. This class contains the implementation of the actual WebDAV requests as well as the common properties such as ExProps. The method in which the WebDAV call is made is GetDAVResponse, which is handed the XML body of the request encoded as a byte array, and a prepackaged System.Net.WebRequest (code written in VB.NET).

'GetDAVResponse is the main method of the whole assembly. 

'This is where we actually communicate with the Exchange Store.

Friend Function GetDAVResponse(ByVal arrData() As Byte, _
        ByVal HTTPRequest As WebRequest) As ExResponse

  Dim oResponse As WebResponse
  Dim oStreamIn As Stream
  Dim oHTTPResp As HttpWebResponse
  Dim oResponseXML As New XmlDocument()
  Dim oStreamRead As StreamReader
  Dim sResp As String
  Dim oExResp As ExResponse
  Dim sCode As String = ""
  Dim sDesc As String = ""
  Dim oStream As Stream

  Try
    'If body data has been submitted add it to the request stream

    If Not arrData Is Nothing Then
      Dim oStreamOut As Stream = HTTPRequest.GetRequestStream()
      oStreamOut.Write(arrData, 0, arrData.Length)
      oStreamOut.Close()
    End If

    'This is where the request is sent and the response recieved

    oResponse = HTTPRequest.GetResponse()

    'Use an HTTPWebResponse object so we can get more info

    oHTTPResp = oResponse

    'Get the Response stream and read it into a string

    oStreamIn = oResponse.GetResponseStream()
    oStreamRead = New StreamReader(oStreamIn)
    sResp = oStreamRead.ReadToEnd()

    'Some requests have no resulting response bodies so set a default one

    If sResp ="" Then
      sResp = "<?xml version=""1.0""?><NoResponse></NoResponse>"
    End If

    'Set up the ExResponse

    object that we will be returning

    oExResp = New ExResponse(m_URI, sResp, oHTTPResp.StatusCode, _
                     oHTTPResp.StatusDescription, oHTTPResp)

  Catch myWebEx As WebException

    'This is where we will end up if the server 

    'the resource is on returns an error

    'So we setup an ExDavException to throw.

    oHTTPResp = myWebEx.Response

    If Not oHTTPResp Is Nothing Then
      sCode = oHTTPResp.StatusCode
      sDesc = oHTTPResp.StatusDescription
    End If

    sResp = "<?xml version=""1.0"" ?><" & _
        "EXDAVError type=""WebRequest Error""><Code>" & _
        sCode & "</Code><Description>" & _
        sDesc & "</Description><Message>" & _
        myWebEx.Message & "</Message></EXDAVError>"
    
    Dim sMsg as String = "There was an error _
              processing the web request." & _
              "See the ErrXML property for more details."

    oExResp = New ExResponse(m_URI, sResp, sCode, sDesc, oHTTPResp)
    Throw New ExDAVException(m_URI, sMsg, sResp, oHTTPResp)

  Catch myEx As Exception

    'Any other exception puts us in here, 

    'so throw a generic ExDavException

    Dim sMsg as String = "There was an error processing _
                         the web request." & _
                         "See the ErrXML property _
                         for more details."

    Throw New ExDAVException(m_URI, sMsg, sResp)

  End Try

  'Return the response

  GetDAVResponse = oExResp

End Function

There are two main classes used when making WebDAV calls using .NET: the System.Net.WebRequest class, and the System.Net.WebResponse. There are two other classes that inherit from these classes, System.Net.HttpWebRequest and System.Net.HttpWebResponse, which have extra functionality for using the HTTP protocol. The WebRequest in this method is pre packaged, and passed in as a parameter as mentioned before, along with the XML body content. Here is a sample of what the code looks like for creating and setting up a WebRequest and the XML body content:

'Instantiate the web request

Dim oHTTP As WebRequest = CType(WebRequest.Create(MyBase.uURI.ToString), 
                                                               WebRequest) 

'Encode the body and get the bytes.

'The body contains XML in the standard WebDAV schema.

Dim bytes() As Byte = Encoding.ASCII.GetBytes(sXML)

'Build the request and its headers

oHTTP.Credentials = MyBase.Credential
oHTTP.ContentType = "text/xml"
oHTTP.ContentLength = bytes.Length
oHTTP.Method = "PROPFIND"
oHTTP.Headers.Add("Depth", sDepth)
oHTTP.Headers.Add("Brief", "t")

This is really all there is to it: create a WebRequest, write the WebDAV XML content to the WebRequest's request stream, then make the call and get the response by using the WebRequest's GetResponse method. Finally the WebResponse's GetResponseStream method is used to retrieve the XML response that was sent by the server.

In order to convert this raw XML from the server into an object model or ADO.NET DataSet, we use an XSLT transform. This transform converts the raw XML into a schema that can be deserialized into an object, or read into a DataSet. For details, see the source code under the ExResponse class. There are obvious performance issues with this approach if large amounts of data are involved, and I would love to hear suggestions on better ways to do this. We have found, however, that the ability to access the data as a recursive object, or as a DataSet is much more useful than as raw XML.

Updates

As changes occur, I'll post them here.

  • August 2nd, 2005 - As mentioned in the final paragraph, the ExObject and ADO.NET DataSets require an XSLT transform. These XSLT stylesheets can be found at ExTransform.xslt and DsTransform.xslt. These style sheets will no longer be available at the locations specified in the code. Please download these stylesheets and save them onto a web server and change the lines 1361 and 1433 to reflect the new locations of these stylesheets. Alternatively, you can download them and embed them as a resource. This will take more modification of the code, but eliminates the dependency on the stylesheets being available online. There is a description of how to do this in the discussion below.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here