In the chapter, you saw how to configure a SOAP extension to run with a particular Web method by applying a custom attribute to that method. However, there's a second way to configure a SOAP extension. Instead of applying attributes one method at a time, you can use a configuration file to cause a SOAP extension to run with every Web method in the scope of the configuration file.
Estimated Time : 35 minutes.
Create a new Visual Basic .NET Class Library in the Visual Studio .NET IDE. Name the new library SoapExt.
Rename the default Class1.vb file to SoapDisplayExtension.vb.
Right-click the References node in Solution Explorer and select Add Reference. Add a reference to System.Web.Services.dll.
Add this code to SoapDisplayExtension.vb:
Imports System.IO Imports System.Text Imports System.Web.Services Imports System.Web.Services.Protocols Namespace SDE Public Class SoapDisplayExtension Inherits SoapExtension ' Variables to hold the original ' stream ' and the stream that we return Private originalStream As Stream Private internalStream As Stream ' Called the first time the ' Web service is used ' Version called if ' configured with an attribute Public Overloads _ Overrides Function _ GetInitializer(_ ByVal methodInfo As _ LogicalMethodInfo, _ ByVal attribute As _ SoapExtensionAttribute) _ As Object ' Not used in this example, ' but it's declared ' MustOverride in ' the base class End Function ' Version called if configured ' with a config file Public Overloads _ Overrides Function _ GetInitializer(_ ByVal WebServiceType As Type) _ As Object ' Not used in this example, ' but it's declared ' MustOverride in the ' base class End Function ' Called each time the ' Web service is used ' And gets passed the ' data from GetInitializer Public Overrides Sub Initialize(_ ByVal initializer As Object) ' Not used in this example, ' but it's declared ' MustOverride in ' the base class End Sub ' The Chainstream method ' gives us a chance ' to grab the SOAP messages ' as they go by Public Overrides _ Function ChainStream(_ ByVal stream As Stream) As Stream ' Save the original stream originalStream = stream ' Create and return our ' own in its place internalStream = _ New MemoryStream() ChainStream = internalStream End Function ' The ProcessMessage method is ' where we do our work Public Overrides Sub _ ProcessMessage(_ ByVal message As SoapMessage) ' Determine the stage ' and take action Select Case message.Stage Case SoapMessageStage. _ BeforeSerialize ' About to prepare ' a SOAP Response Case SoapMessageStage. _ AfterSerialize ' SOAP response is ' all prepared ' Open a log file and ' write status line Dim fs As _ FileStream = _ New FileStream(_ "c:\temp\SDE.log", _ FileMode.Append, _ FileAccess.Write) Dim sw As _ New StreamWriter(fs) sw.WriteLine(_ "AfterSerialize") sw.Flush() ' Copy the passed ' message to the file internalStream. _ Position = 0 CopyStream(_ internalStream, fs) fs.Close() ' Copy the ' passed message to ' the other stream internalStream. _ Position = 0 CopyStream(_ internalStream, _ originalStream) internalStream. _ Position = 0 Case SoapMessageStage. _ BeforeDeserialize ' About to handle a ' SOAP request ' Copy the passed ' message to ' the other stream CopyStream(_ originalStream, _ internalStream) internalStream. _ Position = 0 ' Open a log file ' and write status line Dim fs As _ FileStream = _ New FileStream(_ "c:\temp\SDE.log", _ FileMode.Append, _ FileAccess.Write) Dim sw As New _ StreamWriter(fs) sw.WriteLine(_ "BeforeDeserialize") sw.Flush() ' Copy the passed _ ' message to the file CopyStream(_ internalStream, fs) fs.Close() internalStream. _ Position = 0 Case SoapMessageStage. _ AfterDeserialize ' SOAP request has ' been deserialized End Select End Sub ' Helper function to copy one ' stream to another Private Sub CopyStream(_ ByVal fromStream As Stream, _ ByVal toStream As Stream) Try Dim sr As New _ StreamReader(fromStream) Dim sw As New _ StreamWriter(toStream) sw.WriteLine(_ sr.ReadToEnd()) sw.Flush() Catch ex As Exception End Try End Sub End Class End Namespace
Select Build, Build Solution to compile the class library.
Locate the bin folder of the WeatherService solution that you developed in Step By Step 5.6. Copy the compiled SoapExt.dll file to this folder.
In the WeatherService solution, right-click the References folder and select Add Reference. Add a reference to the SoapExt.dll file that you just copied .
Open the web.config file from the WeatherService solution. Add this code at the bottom of the file (the existing closing tags are shown in bold):
<webServices> <soapExtensionTypes> <add type="SoapExt.SDE.SoapDisplayExtension, SoapExt" priority="1" group="0" /> </soapExtensionTypes> </webServices> </system.web> </configuration>
Select Build, Build Solution to compile the WeatherService project.
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.
Open the SDE.log file in your c:\Temp folder to view the SOAP request and response.
When you configure a SOAP extension in a config file, the extension applies to all Web methods within the scope of the file. If you add a SOAP extension to the machine.config file, the extension will be used with all Web methods served from that computer.
The type attribute of the add tag specifies the SOAP extension to use. There are two parameters within this attribute. The first is the fully-qualified classname of the extension class. The second is the name of the dll file containing the class, without the dll extension.
The priority attribute of the add tag specifies the relative priority of the SOAP extension as compared to other SOAP extensions. The lower the priority value, the higher the relative priority.
The group attribute of the add tag specifies whether the SOAP extension is in group 0 or group 1. SOAP extensions in group 0 are all executed first, in order of their relative priority. After that, SOAP extensions configured via attributes are executed. Finally, SOAP extensions in group 1 are executed, in order of their relative priority.
Describe the round-trip process of a Web method invocation.
When the client calls a Web method, the call is serialized into a SOAP request and sent to the server. On the server, the SOAP request is deserialized into objects and processed by the Web method code. The results of the call are then serialized into a SOAP response and sent to the client. On the client, the SOAP response is deserialized into the results of the call.
At what points in the Web method lifecycle can SOAP extensions modify messages?
SOAP extensions can modify messages before or after serialization or deserialization on either the client or the server.
What is the difference between the GetInitializer method and the Initialize method in a SOAP extension?
The GetInitializer method is called once when a SOAP extension is first loaded, and it can return an arbitrary object. The Initialize method is called each time that the SOAP extension is invoked, and it is passed the object that the GetInitializer method returned.
Name two ways to run code when an asynchronous Web method call completes its work.
You can run code when an asynchronous Web method call is finished by supplying a delegate callback or by using a WaitHandle object to notify you when the results are ready.
What are two ways in which parameters can be formatted in a SOAP message?
Parameters in a SOAP message can be formatted using literal formatting or using SOAP section 5 encoding.
What are two ways that the body of a SOAP message can be formatted?
The body of a SOAP message can be formatted in document style or in SOAP section 7 RPC style.
How can you control the name of a parameter within a SOAP message?
You can use the XmlElement attribute to control the name of a parameter within a SOAP message.
How can you configure a SOAP extension to apply to all Web methods on a computer?
If you specify a SOAP extension within the machine.config file, it will be called for all Web methods invoked on that server.
You are installing two SOAP extensions to a particular Web service. The first extension, named SoapEncrypt, is designed to encrypt SOAP messages using symmetric cryptography. The second extension, named SoapTranslate, is designed to translate key words in the SOAP message from English to French.
You want the SoapTranslate extension to be invoked before the SoapEncrypt extension. Which priorities should you set for the two extensions?
B. SOAP extensions with a lower priority value are invoked first. The lowest possible priority value is zero.
You are developing a SOAP extension that will record the average number of requests for a particular Web method each minute. These results will be written to a file for later analysis. The filename is specified in a configuration file, and will not change while the Web service is running. In which method should you read the name of this file?
A. The filename can be read once at the time when the SOAP extension is first loaded. The GetInitializer method is called at this time. The Initialize method is called every time the SOAP extension is invoked; setting up the file in this method would result in duplication of effort.
You are creating a SOAP extension to log incoming SOAP request messages. In the ChainStream method of the SOAP extension, you have the following code:
Private originalStream As Stream Private internalStream As Stream Public Overrides Function ChainStream(_ ByVal stream As Stream) As Stream originalStream = stream internalStream = New MemoryStream() ChainStream = internalStream End Function
In the ProcessMessage method of the SOAP extension, you have the following code:
Public Overrides Sub ProcessMessage(_ ByVal message As SoapMessage) Select Case message.Stage Case SoapMessageStage. _ BeforeDeserialize Dim sr As New _ StreamReader(internalStream) Dim sw As New _ StreamWriter(originalStream) sw.WriteLine(sr.ReadToEnd()) sw.Flush() LogMessage(internalStream) internalStream.Position = 0 End Select End Sub
You have tested the LogMessage procedure and have verified that it works as desired. When you deploy this SOAP extension, users of your Web service report that they are receiving an error indicating that the root element is missing whenever they attempt to invoke a Web method from the service.
How should you fix this problem?
A. If your SOAP extension is called during deserialization, the original variable will contain the SOAP message, and you should copy it to the internal variable before you finish processing. As the code is currently structured, it copies the empty internal variable over the incoming request, causing the Web service to return an empty string.
You are designing a SOAP extension to modify incoming Web method calls. The extension will run on the server, and when it discovers an obsolete parameter name in the SOAP request, it will replace this with the new parameter name. In which message stage should you invoke this SOAP extension?
C. On the server side, incoming SOAP requests are deserialized into objects. The raw XML is available to be altered in the BeforeDeserialize message stage.
You are designing a SOAP extension to modify outgoing Web method calls. The extension will run on the client, and when it discovers an obsolete parameter name in the SOAP request, it will replace this with the new parameter name. In which message stage should you invoke this SOAP extension?
B. On the client side, outgoing SOAP requests are serialized from objects into XML. The XML is available in the AfterSerialize message stageafter which it is sent to the server.
You are developing a client-side SOAP extension named TraceExt. Your project includes the TraceExt class, and an attribute class named TraceExtAttribute. It also includes a form with a button that invokes a Web method using the following code:
Private Sub btnRunMethod_Click(_ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnRunMethod.Click ' Call a Web method on the Sales object Dim S As SalesWebService.Sales = _ New SalesWebService.Sales() txtSales.Text = S.GetSales() End Sub
Where should you apply the TraceExtAttribute attribute in order to activate the SOAP extension?
D. To invoke a SOAP extension, you can add an attribute for the extension to the Web method declaration. On the client side, you'll find this declaration in the proxy class.
Your code is making asynchronous calls to two different Web methods. You want other processing in your code to continue while these methods execute. When either asynchronous call is finished, you want to process its results. How should your code wait for the results of the asynchronous calls?
B. Using any of the WaitHandle methods will block your code at the point in which the WaitHandle method is called, until the method that you are waiting for returns. To continue processing until the results of the Web methods are available, you should use callback delegates.
Your code is making asynchronous calls to two different Web methods. You then execute other code until you arrive at a point in which you require results from one or the other of the asynchronous calls. You can proceed with further processing as soon as either result is available How should your code wait for the results of the asynchronous calls?
C. The WaitHandle.WaitAny() method will block your code until any of the objects that it's waiting for are available. You can't use callback delegates in this situation because they won't block the code. You can't use separate WaitHandle.WaitOne() methods because the first one will block until its object is ready, and you can't use WaitHandle.WaitAll() because it requires all the objects that it's waiting for to be ready before it proceeds.
You are writing a Web service named Sales in Visual Basic .NET. The Web service will be consumed by a client that expects to use SOAP Section 7 formatting for all messages and SOAP Section 5 formatting for all parameters. How should you declare the Sales Web service?
D. For SOAP section 7 messages, you need to use the SoapRpcService attribute. This attribute automatically uses SOAP section 5 encoding for parameters; it does not include a Use property because this can't be configured.
You are developing a Web service to work with an existing client application. The client application generates SOAP requests in this form:
<?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> <CustomerID xmlns= "http://sales.myco.com/">427 </CustomerID> <OrderID xmlns= "http://sales.myco.com/">18918 </OrderID> </soap:Body> </soap:Envelope>
Which Web service declaration can you use to process these messages?
C. The SOAP message does not have a top-level element wrapping all the parameters, so you must use the Bare parameter style. It also does not include any SOAP section 7 encoding, so you must use document-style body formatting. Finally, the parameters do not include SOAP section 5 encoding, so you must use literal parameters.
You have created a Web method named GetSales with the following declaration:
<WebMethod()> GetSales (_ strCompanyName As String) As Integer
Your corporate standards call for using Hungarian naming (with the str prefix) for variables. However, the developer of the client application that will call this Web method used the name CompanyName (without a prefix) for the parameter. How should you fix this problem?
C. The XmlElement attribute allows you to specify a name for a parameter in a SOAP message different from the name that you use in your actual code. Although rewriting the code would solve the problem, there's no reason to ignore corporate standards when you don't have to do so.
Your Web service includes a SOAP extension named Ext1 which is activated using an attribute. The priority of this extension is set to 3. Now you are modifying the configuration file for the Web service to activate another SOAP extension named Ext2. The Ext2 extension should run after the Ext1 extension. Which section should you add to the web.config file?
C. Extensions configured with group="1" run after extensions configured with an attribute. It's not syntactically legal to specify group="2". Extensions configured with group="0" run before extensions configured with an attribute, regardless of their relative priority values.
You have deployed a Web service and a set of client applications. Now you are ready to deploy version 2 of the Web service, which changes the name of a parameter in one of the Web methods. How can you deploy version 2 of the Web service without breaking the version 1 clients ?
D. The SOAP extension can rewrite incoming SOAP requests before they are deserialized into objects. The XmlElement attribute won't work because it specifies the only name to use, not an alternate name. Exception handling won't work because the code will fail during deserialization before the Web method is actually called.
You have developed a SOAP extension that will compress messages on the server and then decompress them on the client. You plan to use this extension for both requests and responses. Which of these processing stages would be an appropriate place to call this extension? (Select two.)
B, C. This extension will need to be called during the AfterSerialize and BeforeDeserialize stages on both client and server. These are the stages during which you can work with the raw messages as they are passed over the wire.
Your code has made an asynchronous call to a Web method and is now continuing with processing. You've reached a point in which you could handle the return value from the asynchronous call, if it's available, or continue with other processing. How can you check to see whether the asynchronous call is finished without blocking?
A. The IsCompleted property returns True if the results of the asynchronous Web method call are available, without blocking the code where you check the property.
1. Visual Studio .NET Combined Help Collection
Altering the SOAP message using SOAP Extensions
Accessing an XML Web Service Asynchronously in Managed Code
Customizing SOAP messages
2. Scribner, Kenn and Stiver, Mark C. Applied Soap: Implementing .NET XML Web Services . Sams, 2001.
3. Jennings, Roger. Visual Basic .NET XML Web Services Developer's Guide . McGraw-Hill/Osborne, 2002.
4. Oellerman, William. Architecting Web Services . Apress, 2002.