So far in this book, we've been treating the SOAP format as if it were 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 both for 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 can be broken up into multiple elements inside the message body. Elements can be wrapped within an overall element or can be 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 valid 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 messages, so 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 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 that calls 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. To demonstrate the effect of various attributes, we'll use a simple Web service class with a supporting class. Take the following steps to create this Web service: Add a new Visual C# ASP.NET Web Service project (Example6_3) to the solution. In the Solution Explorer, rename the default Service1.asmx to WeatherService.asmx. Open the service in Code view and change all occurrences of Service1 to refer to WeatherService instead. Add the WebService attribute to the WeatherService class definition: [WebService(Namespace="http://WeatherService.TechContent.com")] Add a new class (WindObservation.cs) and add the following code: using System; namespace Example6_3 { public class WindObservation { public string Direction; public int Speed; } } Switch to Code view of the Weather.asmx Web service and add the following using directive: using System.Web.Services.Description; using System.Web.Services.Protocols; Add two Web methods to the Weather.asmx.cs file: [WebMethod()] public bool Store(string Station, WindObservation Wind) { // Return true to indicate success // A full implementation would store the data in the database return true; } [WebMethod()] public WindObservation GetLatest(string Station) { // Simulate retrieving the most recent observation from the database WindObservation w = new WindObservation(); w.Direction = "NNW"; w.Speed = 14; return w; } Build and run the project. Test the Web service by invoking the Web methods. 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. Take the following steps to use literal parameter formatting in a Web service: In Example6_3, apply the following attribute to the WeatherService class: [SoapDocumentService(Use=SoapBindingUse.Literal), WebService(Namespace="http://WeatherService.TechContent.com")] ![graphics/tip_icon.gif](/books/1/425/1/html/2/images/0789728974/graphics/tip_icon.gif) | 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 with a specific Web method. Finally, you can use either one of these attributes in a proxy class to specify the corresponding format on the client side. |
Build the project. Launch .NET WebService Studio. Enter http://localhost/EC70320/C06/Example6_3/WeatherService.asmx as the WSDL endpoint and click the Get button. Select the Invoke tab and click on the Store() Web method. In the Input tree view, 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() Web 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-16"?> <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://WeatherService.TechContent.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-16"?> <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://WeatherService.TechContent.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://WeatherService.TechContent.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 both 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 receives. Using Encoded Parameter Formatting Encoded parameter formatting inserts additional information into the SOAP messages to conform with Section 5 of the SOAP specification. Take the following steps to learn how to specify encoded parameter formatting in a Web service. In Example6_3, apply the following attribute to the WeatherService class: [SoapDocumentService(Use=SoapBindingUse.Encoded), WebService(Namespace="http://WeatherService.TechContent.com/")] Build the Web service and then test it by using the .NET WebService Studio. Select the Request/Response tab to view the SOAP request and the SOAP response. You'll find a SOAP request similar to this: <?xml version="1.0" encoding="utf-16"?> <soap:Envelope xmlns:soap= "http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc= "http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://WeatherService.TechContent.com/" xmlns:types="http://WeatherService.TechContent.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 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-16"?> <soap:Envelope xmlns:soap= "http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc= "http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://WeatherService.TechContent.com/" xmlns:types="http://WeatherService.TechContent.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 that are 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 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 the .NET Framework is a consideration. However, this standards compliance comes at the cost of additional message size. 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. Take the following steps to learn how to use of RPC-style body formatting in a Web service: In Example6_3, apply the following attribute to the WeatherService class: [SoapRpcService(), WebService(Namespace="http://WeatherService.TechContent.com/")] ![graphics/note_icon.gif](/books/1/425/1/html/2/images/0789728974/graphics/note_icon.gif) | You also can apply a SoapRpcMethod attribute to format an individual Web method with the RPC style. |
Build the Web service and then test it by using the .NET WebService Studio. You'll find a SOAP request similar to this: <?xml version="1.0" encoding="utf-16"?> <soap:Envelope xmlns:soap= "http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc= "http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://WeatherService.TechContent.com/" xmlns:types="http://WeatherService.TechContent.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 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-16"?> <soap:Envelope xmlns:soap= "http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc= "http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://WeatherService.TechContent.com/" xmlns:types="http://WeatherService.TechContent.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 the RPC-style encoding example to the encoded parameter example, you'll discover that they're identical! What's going on here? The answer is that the document-style 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 the document style, though, you can supply additional options to the SoapDocumentService attribute. We cover those in the next section. ![graphics/alert_icon.gif](/books/1/425/1/html/2/images/0789728974/graphics/alert_icon.gif) | If you select an RPC-style message body, the parameters within that body automatically are 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. Follow these steps to see how this works: In Example6_3, apply the following attribute to the WeatherService class so that it uses document body formatting and bare literal parameters: [SoapDocumentService(Use=SoapBindingUse.Literal, ParameterStyle=SoapParameterStyle.Bare), WebService(Namespace="http://WeatherService.TechContent.com/")] Build the Web service and then test by using the .NET WebService Studio. You'll find a SOAP request similar to this: <?xml version="1.0" encoding="utf-16"?> <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://WeatherService.TechContent.com/"> AAA</Station> <Wind xmlns="http://WeatherService.TechContent.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-16"?> <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://WeatherService.TechContent.com/"> true</StoreResult> </soap:Body> </soap:Envelope> If you compare this with the literal parameter encoding, you'll see that the bare parameter formatting makes the parameter elements direct children of the <soap:Body> element instead of 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 that you should be aware of involves the XmlElement attribute. This attribute enables you to specify the low-level XML formatting details for messages. You can customize the Web method by applying an XmlElement attribute to individual parameters, as shown here: [WebMethod()] public bool Store( [System.Xml.Serialization.XmlElement("ReportingStation")]string Station, [System.Xml.Serialization.XmlElement("WindReading")]WindObservation Wind) You'll then find this SOAP request: <?xml version="1.0" encoding="utf-16"?> <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> <ReportingStation xmlns="http://WeatherService.TechContent.com/">AAA </ReportingStation> <WindReading xmlns="http://WeatherService.TechContent.com/"> <Direction>N</Direction> <Speed>5</Speed> </WindReading> </soap:Body> </soap:Envelope> Ordinarily, the parameter names within a SOAP message exactly match the parameter names in the Visual C# .NET code for the corresponding Web method. In the previous example, we've used the XmlElement attribute to override the default naming. 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(ElementName="Name", Form=XmlSchemaForm.Qualified)] Table 6.1 shows the properties of the XmlElement attribute that you can set. You can find more information about the XmlElement attribute by looking at the documentation of the XmlElementAttribute class. Table 6.1. Properties of the XmlElement AttributeProperty | Description |
---|
DataType | XSD data type to use for the element. | ElementName | Name of the element. This is the default property. | Form | Whether to use a namespace qualifier with the element name. | IsNullable | Whether to include an element in the XML for null values. | Namespace | Namespace of the element. | Type | Native data type of the element. | |