Building Web Services


This next section will show you how to create your own web services and give you information on dealing with irregular and complex data types, state maintenance, and more. More advanced web service topics will be covered in later chapters.

Hello World

The first sample of a web service that you'll see is the default web service that you create within Visual Studio .NET 2003. To follow along, create a new Web Service project in Visual Studio .NET 2003 and call it WSChapter32. Delete the Service1.asmx file and add a new web service to the project called HelloService.asmx. The code for HelloService is contained in Listing 32.1.

Listing 32.1. The Code-Behind for the Simple Hello World Web Service
 using System; using System.Collections; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Web; using System.Web.Services; namespace WSChapter32 {   /// <summary>   /// Summary description for HelloService.   /// </summary>   [WebService(Namespace="http://www.samspublishing.com/csharpunleashed/chapter32")]   public class HelloService : System.Web.Services.WebService   {     public HelloService()     {        //CODEGEN: This call is required by the ASP.NET Web Services Designer        InitializeComponent();     }     // Component designer code cut out for clarify     // WEB SERVICE EXAMPLE     // The HelloWorld() example service returns the string Hello World     // To build, uncomment the following lines then save and build the project     // To test this web service, press F5     [WebMethod(Description="This method will return 'Hello World'")]     public string HelloWorld()     {       return "Hello World";     }   } } 

To see what this actually produces, without writing a web service client, Visual Studio .NET gives you the ability to see the service from a web page. If your web server is your local machine, you should now be able to pull up http://localhost/WSChapter32/Hello.asmx. The page you see should look a lot like the page in Figure 32.1.

Figure 32.1. The Hello.asmx page rendered by Internet Explorer.


Figure 32.1 shows that the web service has only one method: HelloWorld. As per a code attribute in the code, this page indicates that the HelloWorld method will return the string 'Hello World'.

Clicking the link to the HelloWorld method, you see that the page actually shows you sample SOAP envelopes that can be used for communicating with the service. Those are shown here:

 <?xml version="1.0" encoding="utf-8"?> <soap:Envelope   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns:xsd="http://www.w3.org/2001/XMLSchema"   xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">   <soap:Body>     <HelloWorld xmlns="http://www.samspublishing.com/csharpunleashed/chapter32" />   </soap:Body> </soap:Envelope> 

The SOAP envelope will contain a response from the HelloWorld method:

 <?xml version="1.0" encoding="utf-8"?> <soap:Envelope   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns:xsd="http://www.w3.org/2001/XMLSchema"   xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">   <soap:Body>     <HelloWorldResponse xmlns="http://www.samspublishing.com/csharpunleashed/chapter32">       <HelloWorldResult>string</HelloWorldResult>     </HelloWorldResponse>   </soap:Body> </soap:Envelope> 

If you click the sample Invoke button on the page, you will actually see the SOAP that is returned to the client:

 <?xml version="1.0" encoding="utf-8" ?>   <string xmlns="http://www.samspublishing.com/csharpunleashed/chapter32">Hello World</string> 

This is all great, but as you know, being able to return the string 'Hello World' to a client isn't exactly the most amazing thing. Take a look at what HelloService.asmx might look like if it accepts some simple input parameters. The code for the new HelloService is shown in Listing 32.2.

Listing 32.2. The HelloService Class with a New Method That Takes Parameters
 using System; using System.Collections; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Web; using System.Web.Services; namespace WSChapter32 {   /// <summary>   /// Summary description for Service1.   /// </summary>   [WebService(Namespace="http://www.samspublishing.com/csharpunleashed/chapter32")]   public class HelloService : System.Web.Services.WebService   {     public HelloService()     {       //CODEGEN: This call is required by the ASP.NET Web Services Designer       InitializeComponent();     } // component designer commented out for clarity   // WEB SERVICE EXAMPLE   // The HelloWorld() example service returns the string Hello World   // To build, uncomment the following lines then save and build the project   // To test this web service, press F5     [WebMethod(Description="This method will return 'Hello World'")]     public string HelloWorld()     {       return "Hello World";     }     [WebMethod(Description="This method processes some parameters")]     public string HelloWithParameters( DateTime inTime, int daysToAdd, string userName )     {       return string.Format("Hello, {0}. Your method indicated {1}",         userName, inTime.AddDays(daysToAdd).ToLongDateString());     }   } } 

The new method takes a couple of parameters, performs some processing on them, and returns a string. This is where you can start to see the real power of web services. Obviously the power of a web service isn't in its capability to simply return a static string; it's in the capability to perform some processing and return the result of that processing in a standardized, portable, XML-based format that can be read by any client with a network connection and an XML parser. The output of this method, when supplied with a name and October 10th, 2004 as a starting date with 10 additional days as a parameter, is as follows:

 <?xml version="1.0" encoding="utf-8" ?>   <string     xmlns="http://www.samspublishing.com/csharpunleashed/chapter32">     Hello, Kevin. Your method indicated Wednesday, October 20, 2004</string> 

Complex Serialization

The preceding method and its parameters are fairly simple. You can imagine hundreds of uses for web services that use only simple arguments and simple return types. In addition to the simple types such as strings, integers, and dates, other types can also be utilized by a web service.

Any data type that is passed to or from a web service must be a type that you can represent with an XSD (XML Schema Definition Language) schema. Therefore, you automatically know that all the primitive types, such as integer, string, and date, are supported because they are supported by XSD. But what about things such as ArrayLists, simple arrays, or even very complex objects such as DataSets?

A complex data type can be used with a .NET web service if the data type can be serialized and if its data structure can be represented in XSD.

Listing 32.3 shows the new web service class, complete with a method that returns an ArrayList, one that returns an array of strings, and one that returns a DataSet. You will see that the web service will return very different responses based on these complex, serializable data types.

Listing 32.3. The New HelloService Class That Returns Complex Data to The Client
 using System; using System.Collections; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Web; using System.Web.Services; namespace WSChapter32 {   /// <summary>   /// Summary description for Service1.   /// </summary>   [WebService(Namespace="http://www.samspublishing.com/csharpunleashed/chapter32")]   public class HelloService : System.Web.Services.WebService   {     public HelloService()     {       //CODEGEN: This call is required by the ASP.NET Web Services Designer       InitializeComponent();     } // Component Designer code commented out for clarity     // WEB SERVICE EXAMPLE     // The HelloWorld() example service returns the string Hello World     // To build, uncomment the following lines then save and build the project     // To test this web service, press F5     [WebMethod(Description="This method will return 'Hello World'")]     public string HelloWorld()     {       return "Hello World";     }     [WebMethod(Description="This method processes some parameters")]     public string HelloWithParameters( DateTime inTime, int daysToAdd, string userName )     {       return string.Format("Hello, {0}. Your method indicated {1}",         userName, inTime.AddDays(daysToAdd).ToLongDateString());     }     [WebMethod(Description="This method returns an ArrayList of strings")]     public ArrayList GetArrayList( int count )     {       ArrayList al = new ArrayList();       for (int x=0; x < count-1; x++)       {         al.Add( x.ToString());       }       return al;     }     [WebMethod(Description="Get String Array")]     public string[] GetStrings( int count )     {       ArrayList al = GetArrayList(count);       string[] results = (string[])al.ToArray(typeof(string));       return results;     }     [WebMethod(Description="Returns a DataSet")]     public DataSet GetDataSet( string dsName )     {       DataSet ds = new DataSet();       ds.DataSetName = dsName;       return ds;     }   } } 

When you test the GetArrayList method, you will get the following results (the results will vary slightly based on your input):

 <?xml version="1.0" encoding="utf-8" ?>  <ArrayOfAnyType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xmlns:xsd="http://www.w3.org/2001/XMLSchema"     xmlns="http://www.samspublishing.com/csharpunleashed/chapter32">   <anyType xsi:type="xsd:string">0</anyType>   <anyType xsi:type="xsd:string">1</anyType>   <anyType xsi:type="xsd:string">2</anyType>   <anyType xsi:type="xsd:string">3</anyType>   <anyType xsi:type="xsd:string">4</anyType>   <anyType xsi:type="xsd:string">5</anyType>   <anyType xsi:type="xsd:string">6</anyType>   <anyType xsi:type="xsd:string">7</anyType>   <anyType xsi:type="xsd:string">8</anyType>   <anyType xsi:type="xsd:string">9</anyType>   <anyType xsi:type="xsd:string">10</anyType>  </ArrayOfAnyType> 

As you can see, an XML document that conforms to the XSD schema is being sent to the client. If you run the test method against the GetStrings method (also using 10 as the count), you will get the following (much simpler) result:

 <?xml version="1.0" encoding="utf-8" ?>  <ArrayOfString     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xmlns:xsd="http://www.w3.org/2001/XMLSchema"     xmlns="http://www.samspublishing.com/csharpunleashed/chapter32">   <string>0</string>   <string>1</string>   <string>2</string>   <string>3</string>   <string>4</string>   <string>5</string>   <string>6</string>   <string>7</string>   <string>8</string>   <string>9</string>   </ArrayOfString> 

Finally, if you run the test method against the GeTDataSet method, you will get output that looks similar to the following:

 <?xml version="1.0" encoding="utf-8" ?>  <DataSet xmlns="http://www.samspublishing.com/csharpunleashed/chapter32">  <xs:schema     xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema"    xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">  <xs:element name="MyDataSet" msdata:IsDataSet="true">  <xs:complexType>   <xs:choice minOccurs="0" maxOccurs="unbounded" />   </xs:complexType>   </xs:element>   </xs:schema> <diffgr:diffgram   xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"   xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1" /> </DataSet> 

As you can see, the DataSet comes across serialized into XML. There is no additional wrapper around the DataSet as there is with simple results. In addition, the schema for the DataSet is included along with a DiffGram that, if this DataSet had any data, would indicate all the data within the DataSet.

Keep in mind that the more complex your parameters and output types are, the less likely it will be that non-.NET clients will be able to create or interpret the information.

Using Transactions with a Web Service

One of the extra options available with .NET web services is the capability for a web service method to be the initiator of a distributed COM+ (see Chapter 40, "COM+ Enterprise Services"). Without going into too much detail, a distributed transaction is one in which actions taken by multiple software components in different locations can contribute to the commitment or rollback of a single unit of work or transaction.

You can use the transactionOption enumeration as an argument to the WebMethod attribute to control the capability of your method to control a COM+ transaction. The options you can set are as follows:

  • Required, RequiresNew The method being invoked will create a new COM+ transaction.

  • NotSupported, Supported, Disabled The method being invoked will not participate in a COM+ transaction.

You will see much more about COM+ transactions and what they are in Chapter 41. You might want to use a distributed transaction if your web service makes several calls to remote systems, and if any of those calls fail, the desired behavior would be for all the actions to be rolled back.

Maintaining State with a Web Service

A common topic with web services is the issue of managing state. With standard ASP.NET web applications, it's pretty easy to assume that if a specific user hasn't requested a page from the server within a period of time, the user's session has expired. Can you be so certain about calls to a web service? What constitutes a session within a web service?

When defining a web service in .NET, session state can be enabled if it is needed through the WebService code attribute. The real problem with maintaining session state is that the client is required to be able to accept cookies, and some web service clients refuse cookies.

Contract-First Programming with Web Services

If you've been following along with the code samples, what you have been doing up until this point is code-first web service programming. In other words, you have been creating a class and using ASP.NET to generate the WSDL contract that clients consume.

A popular trend among web service programmers is to write the contract first and then build the code around the contract. This is done to maximize the ability to communicate between disparate systems. If you define the contract exactly the way you like it, you know that the communication between the client and server should be possible and interpreted properly. On the other hand, if you write the server code first and have ASP.NET generate the WSDL, there is a chance that the client might not be able to parse or interpret the WSDL (such as a Java client trying to deal with custom SOAP headers, and so on).



    Visual C#. NET 2003 Unleashed
    Visual C#. NET 2003 Unleashed
    ISBN: 672326760
    EAN: N/A
    Year: 2003
    Pages: 316

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