Building a Web Service Using C


Building a Web Service Using C#

To give you a sense of programming in C#, we'll also build the free/busy Web service in that language. The difference between the Visual Basic and C# Web services is that the C# Web service uses Outlook Web Access (OWA) to return free/busy information rather than using Collaboration Data Objects (CDO); the C# service also has multiple methods . The C# Web service can return the free/busy information in three ways:

  • As the raw XML returned by OWA

  • As XML that the code formats, which makes the return value easier to understand

  • As an ADO.NET dataset

We'll explore each option in detail.

Returning Raw Free/Busy Information

The first method of the Web service simply returns the raw XML free/busy information from the server. A typical response to this method looks like this:

 <?xml version="1.0" encoding="utf-8" ?> <string xmlns="http://tempuri.org/ "><a:response xmlns:a="WM"> <a:recipients> <a:item><a:displayname>All Attendees </a:displayname><a:type>1</ a:type><a:fbdata>000000000000000000000000000000000000000000000000</a:fbdata></ a:item><a:item><a:displayname>Thomas Rizzo</ a:displayname><a:email type="SMTP">thomriz@thomrizex2kdom.extest.microsoft.com< /a:email><a:type>1</ a:type><a:fbdata>000000000000000000000000000000000000000000000000</a:fbdata></ a:item> </a:recipients> </a:response></string> 

Before we look at the code for this portion of the Web service, we'll first look at how the overall Web service is implemented in C#. As you will see, C# is different from Visual Basic in its syntax and is closer to C or C++. The first thing we need to do is add references to the object libraries we will be using. In Visual Basic, we would use the imports keyword. In C#, we use the using keyword, as shown here:

 using System; using System.Collections; using System.Configuration; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Web; using System.Web.Services; using System.Xml; using System.Xml.Serialization; using System.Xml.XPath; using System.Net; using System.IO; using System.Text; using System.Windows.Forms;    // For SystemInformation.ComputerName API 

Next we need to declare our namespace, our class, and any classes we inherit from. Because this is a Web service, our class will be based on the System.Web.Services.Webservice class. We then initialize some variables that we will use throughout the application: the domain, username, password, and timezone information. The designer then places some implemented code into the application for us.

 namespace FreeBusyService {    /// <summary>    /// Summary description for Service1.    /// </summary>    public class Service1 : System.Web.Services.WebService    {       static String serverName = "";       static String domain = "THOMRIZEX2KDOM";       static String userName = "thomriz";       static String password = "password";       static String TimeString = "T00:00:00-07:00";            public Service1()       {          //CODEGEN: This call is required by the ASP.NET          //Web Services Designer          InitializeComponent();       }            #region Component Designer generated code            //Required by the Web Services Designer       private IContainer components = null;            /// <summary>       /// Required method for Designer support - do not modify       /// the contents of this method with the code editor.       /// </summary>       private void InitializeComponent()       {       }            /// <summary>       /// Clean up any resources being used.       /// </summary>       protected override void Dispose(bool disposing)       {          if(disposing && components != null)          {             components.Dispose();          }          base.Dispose(disposing);       }            #endregion 

Next we implement our methods. As with Visual Basic, we use the WebMethod attribute to expose any of our methods as Web service methods. Here is the code for the raw free/busy method:

 [WebMethod]       public string GetFreeBusyRaw(string SMTPAddress, string FBDate)       {          String retXml = "<response>There was a problem getting the " +                          "Free/Busy data</response>";               try          {             string StartDateTimeString = "";             string EndDateTimeString = "";                  try             {                     DateTime startDate = DateTime.Parse(FBDate);                StartDateTimeString = startDate.Year.ToString("####") +                   "-" + startDate.Month.ToString("0#") + "-" +                   startDate.Day.ToString("0#") + TimeString;                     DateTime endDate = startDate.AddDays(1);                EndDateTimeString = endDate.Year.ToString("####") + "-" +                   endDate.Month.ToString("0#") + "-" +                   endDate.Day.ToString("0#") + TimeString;             }             catch (Exception e)             {                Console.WriteLine(e.ToString());                retXml = "<response>The string wasn't recognized as a " +                         "valid DateTime string</response>";                goto cleanup;             }                  serverName = SystemInformation.ComputerName;             String getURL = "http://" +                serverName +                "/public/?Cmd=freebusy&start=" +                StartDateTimeString +                "&end=" +                EndDateTimeString +                "&interval=30&u=SMTP:" +                SMTPAddress;                  // Create an HTTP GET Request             HttpWebRequest request =                (HttpWebRequest)WebRequest.Create(new Uri(getURL));                  // Put the proper credentials on the request             NetworkCredential credentials =                new NetworkCredential(userName, password, domain);             request.Credentials = credentials;                  // Set the user-agent headers             request.UserAgent = "Mozilla/4.0 (compatible; MSIE 5.01; " +                                 "Windows NT)";                  // Execute the Get request and get the response in a stream             WebResponse results = request.GetResponse();             Stream responseStream = results.GetResponseStream();                  StringBuilder responseString = new StringBuilder();             Byte[] read = new Byte[512];             int bytes = responseStream.Read(read, 0, 512);                  while (bytes > 0)             {                responseString.Append(System.Text.Encoding.ASCII.GetString                                     (read, 0, bytes));                bytes = responseStream.Read(read, 0, 512);             }                  if (responseString.Length != 0)             {                retXml = responseString.ToString();             }             responseStream.Close();          }          catch (Exception e)          {             return e.ToString();          }               cleanup:             return retXml;       } 

The code first takes the date entered by the user of the Web service and parses it. Then it uses the inherent date/time functions in C# to turn the date into a format that OWA will understand, which is YYYY-MM-DDTHH:MM:SS-TZ . The code then adds a day to the date for the free/busy query.

To make our query, the code needs to know which server to query OWA on. The code assumes it is running on an Exchange server, so it uses the SystemInformation class to retrieve the current computer's name . You can change this code to query another server if you want.

The code then generates the URL to pass to OWA that will return the free/busy information. As you can see, OWA requires the start date, the end date, the interval, and the SMTP address of the user to get the free/busy information.

Now that we have our URL, we need a way to call the URL via HTTP. You should get familiar with the HTTPWebRequest and HTTPWebResponse classes because you will use them for any HTTP calls you make, including WebDAV calls to Microsoft Exchange or Microsoft SharePoint Portal Server (SPS). I can't cover all the properties and methods that these classes support, but we will use a lot of the properties and methods that you should know to get started programming with .NET and WebDAV.

The first thing we need to do with the HTTPWebRequest class is to create an instance of the class. We do this by calling the Create method on the WebRequest class and pass in either a string that is a valid URL or a URI object that contains a valid URL. Because HTTPWebRequest inherits from WebRequest , the code just typecasts the returned WebRequest object into an HTTPWebRequest object.

Next we need to set the right credentials on our HTTP calls so they are not rejected by the server. To do this, we create a new instance of the NetworkCredential class, passing the username, password, and domain of the network credential we want to create to the constructor of the class. You can also pass the default credentials of the user currently logged-in or the user who is being impersonated. In ASP.NET, this is usually the anonymous IIS user. To use the default credentials, we can change the code to the following:

 request.Credentials = System.Net.CredentialCache.DefaultCredentials; 

For the sake of simplicity, we'll have the code pass the username and password. In production code, you might want to be able to control and cache credentials that are sent to the server. For example, if Basic authentication is enabled on the server, the credential code will send the username and password in clear text. To control the protocol and username/password combination, to store multiple credentials to different resources, or to cache credentials so you do not have to re-create them on every call, you should use the CredentialCache class. Using this class, you can store multiple credentials that will be used with different authentication types. This class has an Add method that you can leverage to specify the URI of the resource that the credential applies to, the authentication type (such as Basic or NTLM), and the network credential to use. We can use the following code to use the CredentialCache class with the Negotiate authentication type only:

 CredentialCache cache = new CredentialCache(); Cache.Add(new Uri(proxyinstance.Url), "Negotiate" ,           new System.Net.NetworkCredential(username, password, domain)) request.Credentials = cache; 

Once we set our credentials, we must set some properties on our HTTPWebRequest so OWA will think we are a normal Web client making the request and will generate the XML response we need. We do this by using the UserAgent property on our request object. The HTTPWebRequest object has a number of properties that map to the standard HTTP headers that you can set, such as the Accept header, the Content-Type header, and the User-Agent header.

Once we set the header, we're done setting up our request object. To make the actual call to the Web server, we need to call the GetResponse method on our request object. This method returns a WebResponse object. If the request is unsuccessful , we can get the WebException object to see what went wrong.

The WebResponse object returns any headers in the response, the content type of the response, and a stream interface to the response from the server. By passing back a stream, you can use the methods on the Stream class to read and write to the stream.

We need to pass back the raw free/busy XML data as a string, so we must convert the stream returned to us to a string. To do this, we use the new StringBuilder class, which provides methods for creating, appending, removing, replacing, and inserting characters into the string. In the code, we create a new instance of an array of bytes, which we will use to read our string into. If the stream is more than the 512 bytes we originally passed, we append the next set of bytes, which are converted to an ASCII string, to our existing string. Then, if the string is actually nonzero in length, which means that we received a response, this string is passed back as the return value for the method.

Returning Data in XML Format

It might be more useful for the consumer of our Web service to receive XML data that corresponds to the free/busy information for the user rather than the raw XML returned back by OWA. To generate our XML response, we'll use some of the new XML capabilities of the .NET Framework. In particular, we'll use the XmlTextReader , XmlTextWriter , and XmlDocument classes.

The XmlTextReader class provides a fast, noncached, forward-only access method to XML data. The good thing about the XmlTextReader class is that it works interchangeably with the XmlDocument class. You can pass an XmlTextReader to an XmlDocument object. As you can guess, the XmlDocument class is the .NET implementation of the XMLDOM . The XmlTextWriter also allows you to write XML documents to multiple output types, such as a file, the console, or a stream. It's a fast way to generate streams or files that contain XML data.

The following is the code for the free/busy method that returns XML rather than raw free/busy data:

 //WEB SERVICE EXAMPLE         [WebMethod]         public String GetFreeBusyXml(string SMTPAddress, string FBDate)         {             String retXml = "<response>There was a problem getting the Free/ Busy data</response>";             XmlDocument resultDoc = null;                  try             {                 // Get the free/busy data from the server                 String responseString = GetFreeBusyRaw(SMTPAddress, FBDate);                      // Now convert the return value to a byte array to feed                 // into a memory stream                 Byte[] read = Encoding.GetEncoding(1252).GetBytes                               (responseString);                      // Load the XmlDocument object with the results for parsing                 MemoryStream stream = new MemoryStream(read);                 XmlTextReader reader = new XmlTextReader(stream);                 XmlDocument xmlDoc = new XmlDocument();                 xmlDoc.Load(reader);                 XPathDocument xmlPath = new XPathDocument(reader);                      String displayName = "DN";                 String smtpAddress = "SMTP";                 String type = "1";                 String fbData = "10101";                      XmlNodeList xmlNodes = xmlDoc.GetElementsByTagName("*");                      for(int i=0;i < xmlNodes.Count;i++)                 {                     XmlNode xmlCurrentNode = xmlNodes[i];                     if (xmlCurrentNode.Name == "a:displayname")                     {                         displayName = xmlCurrentNode.InnerText;                     }                     else if (xmlCurrentNode.Name == "a:email")                     {                         smtpAddress = xmlCurrentNode.InnerText;                     }                     else if (xmlCurrentNode.Name == "a:type")                     {                         type = xmlCurrentNode.InnerText;                     }                     else if (xmlCurrentNode.Name == "a:fbdata")                     {                         fbData = xmlCurrentNode.InnerText;                     }                 }                                     StringBuilder dataString = new StringBuilder();                      // Build the result XML                 dataString.Append("<?xml version=\"1.0\                                   "?>\n<fbresponse>\n<person>");                 dataString.Append("<displayname>" + displayName +                                   "</displayname>");                 dataString.Append("<email type=\"SMTP\">" + smtpAddress +                                   "</email>");                 dataString.Append(MakeFBDataNode(FBDate, fbData));                 dataString.Append("</person>\n</fbresponse>");                      // Now convert the return value to a byte array to feed                 // into a memory stream                 Byte[] output = Encoding.GetEncoding(1252).GetBytes                                (dataString.ToString());                      // Load the XmlDocument object with the results for parsing                 MemoryStream outputStream = new MemoryStream(output);                 XmlTextReader outputReader = new XmlTextReader(outputStream);                      resultDoc = new XmlDocument();                 resultDoc.Load(outputReader);                      MemoryStream writeStream = new MemoryStream                                            (output.Length * 2 );                 XmlTextWriter outputWriter = new XmlTextWriter(writeStream,                                              Encoding.GetEncoding(1252));                 outputWriter.Formatting = Formatting.Indented;                      resultDoc.WriteTo(outputWriter);                 outputWriter.Flush();                      retXml = System.Text.Encoding.ASCII.GetString                          (writeStream.GetBuffer(), 0, (int)writeStream.Length);                  }             catch (Exception e)             {                 return e.ToString();             }             return retXml;         }      private String MakeFBDataNode(string FBDate, string FBData)         {             String dateString;             StringBuilder retXml = new StringBuilder();                  DateTime DTDate = new DateTime();             try             {                 DTDate = DateTime.Parse(FBDate);                 dateString = DTDate.Month.ToString("0#") + "/" +                     DTDate.Day.ToString("0#") + "/" +                     DTDate.Year.ToString("####");             }             catch (Exception e)             {                 dateString = "Bad Date Format";             }                  retXml.Append( "<fbdata date=\"" + dateString + "\">" );                  DateTime TimeVar = new DateTime(DTDate.Year, DTDate.Month,                                DTDate.Day, 0, 0, 0);                  for (int index = 0; index < FBData.Length; index++)             {                 retXml.Append("<timeslot>");                      retXml.Append("<starttime>");                 retXml.Append(TimeVar.ToShortTimeString());                 retXml.Append("</starttime>");                      retXml.Append("<endtime>");                 retXml.Append(TimeVar.AddMinutes(30).ToShortTimeString());                 retXml.Append("</endtime>");                      retXml.Append("<fbstatus>");                 switch ( FBData[index] )                 {                     case '0':                         retXml.Append("Free");                         break;                     case '1':                         retXml.Append("Tentative");                         break;                     case '2':                         retXml.Append("Busy");                         break;                     case '3':                         retXml.Append("Out Of Office");                         break;                     default:                         retXml.Append("Data Not Available");                         break;                 }                 retXml.Append("</fbstatus>");                      retXml.Append("</timeslot>");                      TimeVar = TimeVar.AddMinutes(30);             }                  retXml.Append( "</fbdata>" );             return retXml.ToString();         } 

Here is an example of the formatted XML returned by this method:

 <?xml version="1.0" encoding="utf-8" ?>   <string xmlns="http://tempuri.org/ "><?xml version="1.0"?> <fbresponse> <person> <displayname>Thomas Rizzo</ displayname> <email type="SMTP">thomriz@thomrizex2kdom.extest.microsoft.com</ email> <fbdata date="01/04/2002"> <timeslot> <starttime>12:00 AM</ starttime> <endtime>12:30 AM</endtime> <fbstatus>Free</fbstatus> </ timeslot> <timeslot> <starttime>12:30 AM</starttime> <endtime>1:00 AM</ endtime> <fbstatus>Free</fbstatus> </timeslot> <timeslot> <starttime>1:00 AM</ starttime> <endtime>1:30 AM</endtime> <fbstatus>Free</fbstatus> </ timeslot> <timeslot> <starttime>1:30 AM</starttime> <endtime>2:00 AM</ endtime> <fbstatus>Free</fbstatus> </timeslot> <timeslot> <starttime>2:00 AM</ starttime> <endtime>2:30 AM</endtime> <fbstatus>Free</fbstatus> </ timeslot> <timeslot> <starttime>2:30 AM</starttime> <endtime>3:00 AM</ endtime> <fbstatus>Free</fbstatus> </timeslot> <timeslot> <starttime>3:00 AM</ starttime> <endtime>3:30 AM</endtime> <fbstatus>Free</fbstatus> </ timeslot> <timeslot> <starttime>3:30 AM</starttime> <endtime>4:00 AM</ endtime> <fbstatus>Free</fbstatus> </timeslot> <timeslot> <starttime>4:00 AM</ starttime> <endtime>4:30 AM</endtime> <fbstatus>Free</fbstatus> </ timeslot> <timeslot> <starttime>4:30 AM</starttime> <endtime>5:00 AM</ endtime> <fbstatus>Free</fbstatus> </timeslot> <timeslot> <starttime>5:00 AM</ starttime> <endtime>5:30 AM</endtime> <fbstatus>Free</fbstatus> </ timeslot> <timeslot> <starttime>5:30 AM</starttime> <endtime>6:00 AM</ endtime> <fbstatus>Free</fbstatus> </timeslot> <timeslot> <starttime>6:00 AM</ starttime> <endtime>6:30 AM</endtime> <fbstatus>Free</fbstatus> </ timeslot> <timeslot> <starttime>6:30 AM</starttime> <endtime>7:00 AM</ endtime> <fbstatus>Free</fbstatus> </timeslot> <timeslot> <starttime>7:00 AM</ starttime> <endtime>7:30 AM</endtime> <fbstatus>Free</fbstatus> </ timeslot> <timeslot> <starttime>7:30 AM</starttime> <endtime>8:00 AM</ endtime> <fbstatus>Free</fbstatus> </timeslot> <timeslot> <starttime>8:00 AM</ starttime> <endtime>8:30 AM</endtime> <fbstatus>Free</fbstatus> </ timeslot> <timeslot> <starttime>8:30 AM</starttime> <endtime>9:00 AM</ endtime> <fbstatus>Free</fbstatus> </timeslot> <timeslot> <starttime>9:00 AM</ starttime> <endtime>9:30 AM</endtime> <fbstatus>Free</fbstatus> </ timeslot> <timeslot> <starttime>9:30 AM</starttime> <endtime>10:00 AM</ endtime> <fbstatus>Free</fbstatus> </timeslot> <timeslot> <starttime>10:00 AM</ starttime> <endtime>10:30 AM</endtime> <fbstatus>Busy</fbstatus> </ timeslot> <timeslot> <starttime>10:30 AM</starttime> <endtime>11:00 AM</ endtime> <fbstatus>Busy</fbstatus> </timeslot> <timeslot> <starttime>11:00 AM</ starttime> <endtime>11:30 AM</endtime> <fbstatus>Busy</fbstatus> </ timeslot> <timeslot> <starttime>11:30 AM</starttime> <endtime>12:00 PM</ endtime> <fbstatus>Free</fbstatus> </timeslot> <timeslot> <starttime>12:00 PM</ starttime> <endtime>12:30 PM</endtime> <fbstatus>Free</fbstatus> </ timeslot> <timeslot> <starttime>12:30 PM</starttime> <endtime>1:00 PM</ endtime> <fbstatus>Out Of Office</fbstatus> </ timeslot> <timeslot> <starttime>1:00 PM</starttime> <endtime>1:30 PM</ endtime> <fbstatus>Out Of Office</fbstatus> </ timeslot> <timeslot> <starttime>1:30 PM</starttime> <endtime>2:00 PM</ endtime> <fbstatus>Out Of Office</fbstatus> </ timeslot> <timeslot> <starttime>2:00 PM</starttime> <endtime>2:30 PM</ endtime> <fbstatus>Free</fbstatus> </timeslot> <timeslot> <starttime>2:30 PM</ starttime> <endtime>3:00 PM</endtime> <fbstatus>Tentative</fbstatus> </ timeslot> <timeslot> <starttime>3:00 PM</starttime> <endtime>3:30 PM</ endtime> <fbstatus>Tentative</fbstatus> </ timeslot> <timeslot> <starttime>3:30 PM</starttime> <endtime>4:00 PM</ endtime> <fbstatus>Tentative</fbstatus> </ timeslot> <timeslot> <starttime>4:00 PM</starttime> <endtime>4:30 PM</ endtime> <fbstatus>Free</fbstatus> </timeslot> <timeslot> <starttime>4:30 PM</ starttime> <endtime>5:00 PM</endtime> <fbstatus>Free</fbstatus> </ timeslot> <timeslot> <starttime>5:00 PM</starttime> <endtime>5:30 PM</ endtime> <fbstatus>Free</fbstatus> </timeslot> <timeslot> <starttime>5:30 PM</ starttime> <endtime>6:00 PM</endtime> <fbstatus>Free</fbstatus> </ timeslot> <timeslot> <starttime>6:00 PM</starttime> <endtime>6:30 PM</e ndtime> <fbstatus>Free</fbstatus> </timeslot> <timeslot> <starttime>6:30 PM</ starttime> <endtime>7:00 PM</endtime> <fbstatus>Free</fbstatus> </ timeslot> <timeslot> <starttime>7:00 PM</starttime> <endtime>7:30 PM</ endtime> <fbstatus>Free</fbstatus> </timeslot> <timeslot> <starttime>7:30 PM</ starttime> <endtime>8:00 PM</endtime> <fbstatus>Free</fbstatus> </ timeslot> <timeslot> <starttime>8:00 PM</starttime> <endtime>8:30 PM</ endtime> <fbstatus>Free</fbstatus> </timeslot> <timeslot> <starttime>8:30 PM</ starttime> <endtime>9:00 PM</endtime> <fbstatus>Free</fbstatus> </ timeslot> <timeslot> <starttime>9:00 PM</starttime> <endtime>9:30 PM</ endtime> <fbstatus>Free</fbstatus> </timeslot> <timeslot> <starttime>9:30 PM</ starttime> <endtime>10:00 PM</endtime> <fbstatus>Free</fbstatus> </ timeslot> <timeslot> <starttime>10:00 PM</starttime> <endtime>10:30 PM</ endtime> <fbstatus>Free</fbstatus> </timeslot> <timeslot> <starttime>10:30 PM</ starttime> <endtime>11:00 PM</endtime> <fbstatus>Free</fbstatus> </ timeslot> <timeslot> <starttime>11:00 PM</starttime> <endtime>11:30 PM</ endtime> <fbstatus>Free</fbstatus> </timeslot> <timeslot> <starttime>11:30 PM</ starttime> <endtime>12:00 AM</endtime> <fbstatus>Free</fbstatus> </ timeslot> </fbdata> </person> </fbresponse></string> 

The code first calls the free/busy raw method to get the raw version of the free/busy information to convert to XML. It loads the string returned into a byte array so the code can load the byte array into a stream object, and then it loads the stream object into an XmlTextReader . Next the code creates a new XmlDocument object and loads the XmlTextReader into the XmlDocument . We now have an XmlDocument filled with the raw XML data that was returned.

To give you an example of how to load an XPathDocument object with the XML data, the code includes a line that loads the XmlTextReader into a new instance of the XPathDocument class. With the XPathDocument class, you can transform the XML document using XSLT or query the document using XPath.

Next the code uses the XML DOM to scroll through the returned free/busy XML document from OWA. The code finds the corresponding free/busy information for the user and loads that information into some variables.

The code then creates a new string using the StringBuilder class, which will contain the formatted XML that we need to send back from the service. As part of the construction of the XML, the MakeFBDataNode function is called. This function takes the data passed to it and creates the timeslot nodes for the formatted XML response.

The code goes through a number of additional steps to create an XmlTextWriter . The XmlTextWriter formats the XML by indenting the child objects by setting the Formatting property to Formatting.Indented . At the end of the code, the method sends back the text version of the formatted XML.

Returning an ADO.NET DataSet

If you have not looked at the data access features of .NET, you should. .NET includes a new set of data access functionality and classes called ADO.NET. Even though ADO.NET sounds similar to ADO, the two object models are very different. You can still use ADO via the COM interoperability layer in .NET. You'll see a sample of using ADO later in this chapter.

ADO.NET includes a number of new objects, such as the DataSet , DataReader , and DataAdapter objects. A DataSet is an in-memory representation of data from a relational or hierarchical datasource. You can put data from an SQL Server into a DataSet or put XML data into a DataSet . The DataSet will maintain the relations and constraints that you assign to that data. You can even pass an ADO Recordset to a DataSet , and it will import the records, as you'll see later in this chapter.

Note that the DataSet will not automatically write back the changed or updated data to the data source unless the DataSet is connected to or related to a DataAdapter , which is similar to an OLEDB data adapter. Unfortunately, neither the EXOLEDB nor the MSDAIPP providers are fully supported via the managed OLEDB providers with .NET. EXOLEDB does support the OLEDB .NET data provider for read-only operations against Exchange or SharePoint. However, the OLEDB .NET data provider expects command syntax such as UPDATE or INSERT in order to update data rather than cursors , which EXOLEDB supports. You cannot modify data in Exchange from the OLEDB .NET provider. The following code snippet shows how to use the OLEDB .NET data adapter against Exchange in Visual Basic:

 On Error Resume Next Dim conn As New OleDb.OleDbConnection("Provider=Exoledb.datasource; " & _     "Data Source=file://./backofficestorage/thomriznt5dom2.extest." & _     "microsoft.com/public folders/folder/")      Dim query As String = "SELECT ""urn:schemas:httpmail:subject"" FROM " & _     "SCOPE('shallow traversal of "file://./backofficestorage/" & _     "thomriznt5dom2.extest.microsoft.com/public folders/folder/""')"      Dim oCmd As New System.Data.OleDb.OleDbCommand(query, conn) conn.Open() Dim oOLEDBReader As System.Data.OleDb.OleDbDataReader oOLEDBReader = oCmd.ExecuteReader While oOLEDBReader.Read()     MsgBox(oOLEDBReader.GetString(0)) End While 

This effectively means you cannot use the included .NET DataAdapter objects with Exchange or SPS. Instead, you can use the non-.NET version of ADO to access your collaborative data or you can use WebDAV and XML with the .NET data access features. You can also write your own data adapter by using WebDAV and XML.

To show you how to use a DataSet with XML, the Web service also returns the results as an ADO.NET DataSet filled with XML data. The following is the code in the service that creates and returns the Dataset :

 [WebMethod]         public DataSet GetFreeBusyDataSet(string SMTPAddress, string FBDate)         {             DataSet resultSet = null;                  try             {                 // Get the free/busy data from the server                 String responseString = GetFreeBusyXml(SMTPAddress, FBDate);                      // Now convert the return value to a byte array to feed                 // into a memory stream                 Byte[] output = Encoding.GetEncoding(1252).GetBytes                                 (responseString);                      // Load the XmlDocument object with the results for parsing                 MemoryStream outputStream = new MemoryStream(output);                 XmlTextReader outputReader = new XmlTextReader(outputStream);                      XmlDataDocument resultDoc = new XmlDataDocument();                 resultDoc.DataSet.ReadXml(outputReader);                 resultSet = resultDoc.DataSet;             }             catch(Exception e)             {                 return resultSet;             }             return resultSet;         } 

The first thing the code does is leverage our existing XML formatted free/busy function to get back the free/busy information for the user. Next it loads a stream with the XML output. That stream is then loaded into an XmlTextReader . Then an XmlDataDocument is loaded with the XmlTextReader . An XmlDataDocument extends the standard XmlDocument class and allows you to load relational or XML data into the class. The XmlDataDocument is closely related to the Dataset class and has a Dataset property, which returns a Dataset that represents the XML data in the XmlDataDocument . The Dataset returned by this property is returned to the caller of the Web service.




Programming Microsoft Outlook and Microsoft Exchange 2003
Programming MicrosoftВ® OutlookВ® and Microsoft Exchange 2003, Third Edition (Pro-Developer)
ISBN: 0735614644
EAN: 2147483647
Year: 2003
Pages: 227
Authors: Thomas Rizzo

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net