Create and Consume an XML Web service: Control XML wire format for an XML Web service.
So far in this book I've been treating the SOAP format as if it is completely specified by the SOAP standard. But, in fact, the standard allows a good deal of flexibility in converting objects to XML messages. There are variations in formatting for both the parameters within the body of a SOAP message and for the format of the body itself:
-
Literal parameter formatting formats parameters according to an XSD schema. This is the default parameter formatting for .NET Web services.
-
Encoded parameter formatting formats parameters according to what are called the SOAP Section 5 encoding rules. These rules encode data type information directly into the SOAP message.
-
Document-based body formatting is the default .NET body formatting. In this method of body formatting, parameters may be broken up into multiple elements inside the message body. Elements may be wrapped within an overall element or placed in the body as bare elements.
-
RPC-based body formatting is sometimes known as SOAP Section 7 formatting. In this style of body formatting, all parameters are contained within a single element in the body of the SOAP message.
Given these choices, there are three different legal combinations:
-
Document-based body formatting with literal parameter formatting (the .NET default)
-
Document-based body formatting with encoded parameter formatting
-
RPC-based body formatting with encoded parameter formatting
These formatting choices control the XML wire format of the messagesso-called because the resulting messages travel "over the wire" between client and server.
You can apply attributes indicating these choices to both Web methods and to proxy classes that call those methods . It should be obvious that you must match such choices: If the Web method is using encoded parameter formatting, any proxy class calling that method must also use encoded parameter formatting.
Finally, you can also use attributes to change details about the SOAP message, such as the names used for XML elements representing parameters.
Why would you make these changes? If you're working in a purely .NET world, you probably wouldn't. But there might come a time when you need to write code that interoperates with Web services developed under other environments or with clients that can't use the .NET defaults. In those cases, it's helpful to be able to fine-tune the XML that your code can accept to match the XML sent and received by less-flexible components .
In this section of the chapter, I'll demonstrate all these choices and their effects on the SOAP messages produced by .NET code. Rather than write entire applications for each option, I'll show you how to modify the Web service code, and then use .NET WebService Studio (http://www.gotdotnet.com/team/tools/web_svc/default.aspx) to display the request and response messages. For more information on .NET WebService Studio, see Chapter 4.
Using Literal Parameter Formatting
Literal parameter formatting is the default for Web services created with Visual Studio .NET. But if you like, you can use attributes to specify this default explicitly. Step By Step 5.6 shows how you can do this.
STEP BY STEP 5.6 Using Literal Parameter Formatting in a Web Service -
Create a new Visual Basic ASP.NET Web Service Application in the Visual Studio .NET IDE. Name the new Web service WeatherService. -
Right-click the Service1.asmx in Server Explorer and select Rename. Change the name of this file to Weather.asmx. -
Right-click the Weather.asmx file in Server Explorer and select View Code. Change the name of the class in the class declaration from Service1 to Weather . Change the Namespace for the class in the WebService attribute to http://weather.que.com/ . -
Add a new class file to the project. Name the new class WindObservation.vb. Modify the WindObservation.vb class to contain this code: Public Class WindObservation Public Direction As String Public Speed As Integer End Class -
Add code at the top of the Weather.asmx.vb file: Imports System.Web.Services Imports System.Web.Services.Description Imports System.Web.Services.Protocols -
Add two Web methods to the Weather.asmx.vb file: <WebMethod()> Public Function Store(_ ByVal Station As String, _ ByVal Wind As WindObservation) As Boolean ' Here a full implementation would store ' the data in the database ' Return True to indicate success Store = True End Function <WebMethod()> Public Function GetLatest(_ ByVal Station As String) As WindObservation ' Simulate retrieving the most ' recent observation from the database Dim w As WindObservation = New WindObservation() w.Direction = "NNW" w.Speed = 14 GetLatest = w End Function EXAM TIP Applying Web Service Attributes In this case, you used the SoapDocumentService attribute to apply formatting to an entire Web service where the service is defined. You can also use the SoapDocumentMethod attribute to a specific Web method. You can also use either one of these attributes in a proxy class to specify the corresponding format on the client side. -
Modify the declaration of the Weather class to specify that it should use document-based body formatting with literal parameters: <SoapDocumentService(Use:=SoapBindingUse.Literal), _ WebService(Namespace:="http://weather.que.com/")> _ Public Class Weather -
Select Build, Build Solution to compile the Web service. -
Launch .NET WebService Studio. Enter http://localhost/WeatherService/Weather.asmx as the WSDL EndPoint and click the Get button. -
Select the Invoke tab and click on the Store method. In the Input treeview, click on the Station parameter. Enter AAA as the value for this parameter. Similarly, enter values of N for the Direction parameter and 5 for the Speed parameter. Click the Invoke button to call the Store method. -
Select the Request/Response tab to view the SOAP request and the SOAP response. You'll find this SOAP request: NOTE Attribute Names If you're looking up attributes in the help files, you'll find them as classes with the word "Attribute" included in their names. For example, the formal name of the SoapDocumentService attribute class is SoapDocumentServiceAttribute. Visual Basic .NET lets you use the shorter form in code. <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap= "http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <Store xmlns="http://weather.que.com/"> <Station>AAA</Station> <Wind> <Direction>N</Direction> <Speed>5</Speed> </Wind> </Store> </soap:Body> </soap:Envelope> You'll also find the corresponding SOAP response: <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap= "http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <StoreResponse xmlns="http://weather.que.com/"> <StoreResult>true</StoreResult> </StoreResponse> </soap:Body> </soap:Envelope> |
As you can see, literal parameter formatting keeps things very simple. Starting from the outside in, here's what you'll find in these messages:
-
The soap:Envelope element, which includes the namespace declarations that identify this as a SOAP message.
-
The soap:Body element, which identifies the application-specific body of the SOAP message.
-
The top level application-specific element (Store or StoreResponse). These elements specify the namespace of the Web service itself ( http://weather.que.com ), indicating that all the contained elements will be from this namespace.
-
Elements representing the actual parameters of the messages. Note that the complex parameter Wind is handled by creating nested XML elements for each of its properties.
Literal parameter formatting does not insert any information about data types into the SOAP messages. It assumes that your code will know how to handle the data that it sends and recieves.
Using Encoded Parameter Formatting
Encoded parameter formatting inserts additional information into the SOAP messages to conform with section 5 of the SOAP specification. Step By Step 5.7 shows how you can specify encoded parameter formatting and displays the results.
STEP BY STEP 5.7 Using Encoded Parameter Formatting in a Web Service -
Start with the Web service that you created in Step By Step 5.6. Modify the declaration of the Weather class to specify that it should use document-based body formatting with encoded parameters: <SoapDocumentService(Use:=SoapBindingUse.Encoded), _ WebService(Namespace:="http://weather.que.com/")> _ Public Class Weather -
Select Build, Build Solution to compile the Web service. -
Launch .NET WebService Studio. Enter http://localhost/WeatherService/Weather.asmx as the WSDL EndPoint and click the Get button. -
Select the Invoke tab and click on the Store method. In the Input treeview, click on the Station parameter. Enter AAA as the value for this parameter. Similarly, enter values of N for the Direction parameter and 5 for the Speed parameter. Click the Invoke button to call the Store method. -
Select the Request/Response tab to view the SOAP request and the SOAP response. You'll find this SOAP request: <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap= "http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc= "http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://weather.que.com/" xmlns:types="http://weather.que.com/encodedTypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body soap:encodingStyle= "http://schemas.xmlsoap.org/soap/encoding/"> <tns:Store> <Station xsi:type="xsd:string">AAA</Station> <Wind href="#id1" /> </tns:Store> <tns:WindObservation id="id1" xsi:type="tns:WindObservation"> <Direction xsi:type="xsd:string">N</Direction> <Speed xsi:type="xsd:int">5</Speed> </tns:WindObservation> </soap:Body> </soap:Envelope> You'll also find the corresponding SOAP response: <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap= "http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc= "http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://weather.que.com/" xmlns:types="http://weather.que.com/" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body soap:encodingStyle= "http://schemas.xmlsoap.org/soap/encoding/"> <types:StoreResponse> <StoreResult xsi:type= "xsd:boolean">true</StoreResult> </types:StoreResponse> </soap:Body> </soap:Envelope> |
Note that encoded parameter formatting is somewhat more complex than literal parameter formatting. The soap:Envelope element includes additional namespaces to allow each parameter to be explicitly marked with its data type. Elements specific to this Web service (such as the method name or the parameter names) are each explicitly marked with the tns namespace indicator. The complex data element Wind is handled by a reference to a separate XML element outside of the tns:Store element.
Encoded parameter formatting conforms more closely to the SOAP standard than literal parameter formatting, and thus might be helpful when interoperability with Web service components defined outside of the .NET Framework is a consideration. However, this standard compliance comes at the cost of additional message size . Table 5.1 shows how the request and response sizes compare between literal and encoded parameter formatting in this simple example.
Table 5.1. Comparison of Literal and Encoded Parameter Formatting
SOAP Message | Literal Size | Encoded Size | Increase |
Request | 368 bytes | 705 bytes | 92% |
Response | 341 bytes | 538 bytes | 58% |
Using RPC-Style Body Formatting
Another major decision to make about SOAP message formatting is whether to use document-style or RPC-style (SOAP Section 7) body formatting. So far, all the SOAP messages you've seen have used document-style body formatting. Step By Step 5.8 demonstrates the use of RPC-style body formatting.
STEP BY STEP 5.8 Using RPC-style Body Formatting in a Web Service -
Start with the Web service that you created in Step By Step 5.6. Modify the declaration of the Weather class to specify that it should use RPC-style body formatting: <SoapRpcService(), _ WebService(Namespace:="http://weather.que.com/")> _ Public Class Weather NOTE Method by Method Encoding There is also a SoapRpcMethod attribute that you can apply to format an individual Web method using RPC style. -
Select Build, Build Solution to compile the Web service. -
Launch .NET WebService Studio. Enter http://localhost/WeatherService/Weather.asmx as the WSDL EndPoint and click the Get button. -
Select the Invoke tab and click on the Store method. In the Input treeview, click on the Station parameter. Enter AAA as the value for this parameter. Similarly, enter values of N for the Direction parameter and 5 for the Speed parameter. Click the Invoke button to call the Store method. -
Select the Request/Response tab to view the SOAP request and the SOAP response. You'll find this SOAP request: <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap= "http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc= "http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://weather.que.com/" xmlns:types="http://weather.que.com/encodedTypes" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body soap:encodingStyle= "http://schemas.xmlsoap.org/soap/encoding/"> <tns:Store> <Station xsi:type="xsd:string">AAA</Station> <Wind href="#id1" /> </tns:Store> <tns:WindObservation id="id1" xsi:type="tns:WindObservation"> <Direction xsi:type="xsd:string">N</Direction> <Speed xsi:type="xsd:int">5</Speed> </tns:WindObservation> </soap:Body> </soap:Envelope> You'll also find the corresponding SOAP response: <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap= "http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc= "http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://weather.que.com/" xmlns:types="http://weather.que.com/" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body soap:encodingStyle= "http://schemas.xmlsoap.org/soap/encoding/"> <types:StoreResponse> <StoreResult xsi:type= "xsd:boolean">true</StoreResult> </types:StoreResponse> </soap:Body> </soap:Envelope> |
If you compare the results of Step By Step 5.8 to those of Step By Step 5.7, you'll discover that they're identical! What's going on here? The answer is that the Document style of body formatting is more flexible than the RPC style. When you use RPC style, you can't make any further choices about how to encode the parameters within the body. With Document style, though, there are additional options that you can supply to the SoapDocumentService attribute. I'll cover those in the next section.
EXAM TIP
RPC Body Forces Encoded Parameters If you select an RPC-style message body, the parameters within that body will automatically be encoded according to the SOAP section 5 rules.
Wrapped and Bare Parameters
In both RPC-style body formatting and the default document body formatting, all the parameters within the SOAP message are contained within a single XML element identified with the name of the Web method. This is referred to as the wrapped parameter style.
If you're using document body formatting, you can specify the bare parameter style as an alternative. Step By Step 5.9 shows you how this works.
STEP BY STEP 5.9 Using Bare Parameters in a Web Service -
Start with the Web service that you created in Step By Step 5.6. Modify the declaration of the Weather class to specify that it should use document body formatting and bare literal parameters: <SoapDocumentService(Use:=SoapBindingUse.Literal, _ ParameterStyle:=SoapParameterStyle.Bare), _ WebService(Namespace:="http://weather.que.com/")> _ Public Class Weather -
Select Build, Build Solution to compile the Web service. -
Launch .NET WebService Studio. Enter http://localhost/WeatherService/Weather.asmx as the WSDL EndPoint and click the Get button. -
Select the Invoke tab and click on the Store method. In the Input treeview, click on the Station parameter. Enter AAA as the value for this parameter. Similarly, enter values of N for the Direction parameter and 5 for the Speed parameter. Click the Invoke button to call the Store method. -
Select the Request/Response tab to view the SOAP request and the SOAP response. You'll find this SOAP request: <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap= "http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <Station xmlns= "http://weather.que.com/">AAA</Station> <Wind xmlns="http://weather.que.com/"> <Direction>N</Direction> <Speed>5</Speed> </Wind> </soap:Body> </soap:Envelope> You'll also find the corresponding SOAP response: <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap= "http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <StoreResult xmlns="http://weather.que.com/"> true</StoreResult> </soap:Body> </soap:Envelope> |
If you compare the results of Step By Step 5.9 with those of Step By Step 5.6, you'll see that the bare parameter formatting makes the parameter elements direct children of the soap:Body element, rather than wrapping them in a single element that represents the entire Web method. You can also apply bare parameter formatting to encoded parameters with similar results.
Using the XmlElement Attribute
The last level of customization of which you should be aware involves the XmlElement attribute. This attribute allows you to specify the low-level XML formatting details for messages, as shown in Step By Step 5.10.
STEP BY STEP 5.10 Using the XmlElement Attribute -
Start with the Web service that you created in Step By Step 5.6. Modify the declaration of the Weather class to specify that it should use document body formatting and literal parameters: <SoapDocumentService(Use:=SoapBindingUse.Literal), _ WebService(Namespace:="http://weather.que.com/")> _ Public Class Weather -
Add an additional line of code at the top of the module: Imports System.Xml.Serialization -
Modify the declaration of the Store method as follows : <WebMethod()> Public Function Store(_ <XmlElement("ReportingStation")> _ ByVal Station As String, _ <XmlElement("WindReading")> _ ByVal Wind As WindObservation) As Boolean As you can see, the XmlElement attribute can be applied to individual parameters. -
Select Build, Build Solution to compile the Web service. -
Launch .NET WebService Studio. Enter http://localhost/WeatherService/Weather.asmx as the WSDL EndPoint and click the Get button. -
Select the Invoke tab and click on the Store method. In the Input treeview, click on the ReportingStation parameter. Enter AAA as the value for this parameter. Similarly, enter values of N for the Direction parameter and 5 for the Speed parameter. Click the Invoke button to call the Store method. -
Select the Request/Response tab to view the SOAP request and the SOAP response. You'll find this SOAP request: <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap= "http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <Store xmlns="http://weather.que.com/"> <ReportingStation>AAA</ReportingStation> <WindReading> <Direction>N</Direction> <Speed>5</Speed> </WindReading> </Store> </soap:Body> </soap:Envelope> You'll also find the corresponding SOAP response: <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap= "http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <StoreResponse xmlns="http://weather.que.com/"> <StoreResult>true</StoreResult> </StoreResponse> </soap:Body> </soap:Envelope> |
Ordinarily, the parameter names within a SOAP message exactly match the parameter names in the VB .NET code for the corresponding Web Method. In Step By Step 5.10, though, I've used the XmlElement attribute to override the default naming in several cases. As you can see in the SOAP messages, the names in the XmlElement attribute are used instead of the default names.
In addition to the element names, you can control other aspects of the generated XML with properties of the XmlElement attribute. For example, you can force the element to include a namespace qualifier with the Form property:
<XmlElement(Name:="ElementName", _ Form:=XmlSchemaForm.Qualified)>
Table 5.2 shows the properties of the XmlElement attribute that you can set.
Table 5.2. Properties of the XmlElement Attribute
Property | Description |
DataType | XSD data type to use for the element. |
ElementName | Name of the element. This is the default property. |
Form | Indicates whether to use a namespace qualifier with the element name. |
IsNullable | Indicates whether to include an element in the XML for null values. |
Namespace | Namespace of the element. |
Type | Native data type of the element. |
REVIEW BREAK -
SOAP messages can be formatted in a variety of ways. You can use literal or encoded parameter formatting, document or RPC-style body formatting, and wrapped or bare parameters. -
The .NET Framework allows you to dictate the format of SOAP messages through applying attributes to the Web service or Web method at both the server and the proxy class. -
The XmlElement attribute allows you to specify the name and other details of a parameter in a SOAP message. |