Creating and Using SOAP Extensions

Team-Fly    

Developing XML Web Services and Server Components with Visual C#™ .NET and the .NET Framework, Exam Cram™ 2 (Exam 70-320)
By Amit Kalani, Priti Kalani

Table of Contents
Chapter 6.  Advanced Web Services


When a Web service client invokes a Web method that is on a Web service server, the client turns the objects and parameters involved into an XML message: the SOAP request. This process of converting objects to XML is called serialization. On the server end, the reverse process (called deserialization) is used to turn the XML back into objects. The server then sends back the SOAP response, which goes through a similar process of serialization and deserialization.

SOAP extensions enable you to run your own code as part of the serialization or deserialization processes. A SOAP extension can perform tasks such as encryption, signature verification, translation, or any other modification of the SOAP messages that are being passed. Figure 6.1 shows schematically how SOAP extensions fit into the Web services architecture.

Figure 6.1. How the Web service communication works with SOAP extensions.

graphics/06fig01.gif

In Figure 6.1, the circles show the points at which you can insert a SOAP extension into the Web services architecture. As you can see, SOAP extensions are quite flexible: You can run code in a SOAP extension before or after a serialization or deserialization operation.

graphics/alert_icon.gif

You can have more than one SOAP extension working with a single SOAP message. The SOAP extension with the lowest priority modifies the message first; the SOAP extension with the highest priority modifies the message last.


SOAP extensions can be deployed on the client or on the server, and alone or in pairs. Here are some examples to suggest how particular types of SOAP extensions might fit into the overall Web services picture:

  • A SOAP extension designed to measure overall server traffic for a Web service would be deployed only on the server. Clients would never know anything about this SOAP extension.

  • A SOAP extension designed to translate requests from English measurements to metric measurements, and responses from metric measurements to English measurements, would be deployed only on the client. As far as the server knows, it's still dealing with a client making requests in metric measurements.

  • A SOAP extension designed to digitally sign messages and to verify the digital signature on delivery would need to be deployed on both the client and the server. Each side would sign outgoing messages and verify incoming signatures.

The following list shows the steps to be followed while creating a SOAP extension:

  1. Derive a new class from the SoapExtension class.

  2. Implement the GetInitializer() and Initialize() methods to handle startup chores.

  3. Implement the ChainStream() method to intercept the SOAP messages being serialized and deserialized.

  4. Implement the ProcessMessage() method to work with the SOAP messages.

  5. Derive a new class from the SoapExtensionAttribute class to mark methods that will use the new extension.

Here's an example that follows these steps:

  1. Create a blank solution using Visual Studio .NET. Name the solution C06 and specify its location as C:\EC70320.

  2. Add a new Visual C# ASP.NET Web Service application project to the solution. Specify http://localhost/EC70320/C06/Example6_1 as the location of the project.

  3. In the Solution Explorer, rename the default Service1.asmx to BugService.asmx. Open the service in Code view and change all occurrences of Service1 to refer to BugService instead.

  4. Apply the following attribute to the class definition of the BugService class:

     [WebService(Namespace="http://BugService.TechContent.com/")] 
  5. Add a new class (Bug.cs) to the project and add the following code:

     using System; namespace Example6_1 {     public class Bug     {         private int bugID;         private string description;         public Bug()         {             Description = "";         }         public Bug(int bugID)         {             this.bugID = bugID;             // Test data, a real implementation would retrieve             // details from a database or other store here             this.description = "Initializing the thingamabob " +                 "causes the whatsit to crash.";         }         public int BugID         {             get {                 return bugID;             }             set {                 bugID = value;             }         }         public string Description         {             get {                 return description;             }             set {                 description = value;             }         }     } } 
  6. Add a new class (SoapDisplayExtension.cs) and add the following using directives:

     Using System; using System.IO; using System.Text; using System.Web.Services; using System.Web.Services.Protocols; 
  7. Modify the SoapDisplayExtension class to derive from the SoapExtension class:

     public class SoapDisplayExtension : SoapExtension 
  8. Add the following two variables to the SoapExtension class:

     private Stream originalStream; private Stream internalStream; 
  9. Add the following two methods to the SoapExtension class:

     // These methods are not specifically used in this example but must // be overridden as they are declared abstract in the base class public override object GetInitializer(System.Type serviceType) {     return null; } public override object GetInitializer(LogicalMethodInfo methodInfo,     SoapExtensionAttribute attribute) {     return null; } public override void Initialize(object initializer) {   return; } 

    graphics/alert_icon.gif

    The GetInitializer() method is called once when your SOAP extension is first initialized. There are two forms of this method, depending on whether the SOAP extension was configured with an attribute or with a configuration file. You can pass any object you want as the return value from the GetInitializer() method. The Initialize() method is called once for every SOAP message serialized or deserialized by the Web service. The object passed to the Initialize() method is the same object that you return from the GetInitializer() method. So, for example, you might open a file in the GetInitializer() method and pass a FileStream object as the return value from that method to become the input parameter to the Initialize() method.


  10. Override the ChainStream() method of the SoapExtension class:

     // The ChainStream() method intercept the SOAP messages as they go by public override System.IO.Stream ChainStream(System.IO.Stream stream) {     // Save the original stream     originalStream = stream;     // Create and return your own in its place     internalStream = new MemoryStream();     return internalStream; } 

    graphics/alert_icon.gif

    If your SOAP extension is called during serialization, the internal variable that you returned contains the SOAP message, and you should copy it to the original variable before you finish processing. 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. Remember, the client serializes requests and deserializes responses, whereas the server deserializes requests and serializes responses.


  11. Add code to handle SOAP messages in the ProcessMessage() method. Note that this method is called in four different situations (before and after serialization and deserialization), and you can use the passed parameter to determine which stage you are in:

     // The ProcessMessage() method is where soap messages are handled public override void ProcessMessage(     System.Web.Services.Protocols.SoapMessage message) {     // Determine the stage and take appropriate action     switch(message.Stage)     {         case SoapMessageStage.BeforeSerialize:             // About to prepare a SOAP Response             break;         case SoapMessageStage.AfterSerialize:             // Open a log file and write a status line             FileStream fs = new FileStream(@"c:\temp\BugService.log",                 FileMode.Append, FileAccess.Write);             StreamWriter sw = 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;             break;         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 a status line             FileStream fs1 = new FileStream(                 @"c:\temp\BugService.log",                 FileMode.Append, FileAccess.Write);             StreamWriter sw1 = new StreamWriter(fs1);             sw1.WriteLine("BeforeDeserialize");             sw1.Flush();             // Copy the passed message to the file             CopyStream(internalStream, fs1);             fs1.Close();             internalStream.Position = 0;             break;         case SoapMessageStage.AfterDeserialize:             // SOAP request has been deserialized             break;     } } // Helper function to copy one stream to another private void CopyStream(Stream fromStream, Stream toStream) {     try     {         StreamReader sr  = new StreamReader(fromStream);         StreamWriter sw = new StreamWriter(toStream);         sw.WriteLine(sr.ReadToEnd());         sw.Flush();     }     catch (Exception ex)     {         // Log the exception     } } 
  12. Add a new class (SoapDisplayExtensionAttribute.cs) and add the following code:

     using System; using System.Web.Services; using System.Web.Services.Protocols; namespace Example6_1 {    [AttributeUsage(AttributeTargets.Method) ]    public class SoapDisplayExtensionAttribute : SoapExtensionAttribute    {         private int priority =1;         public override int Priority         {             get {                 return priority;             }             set {                 priority = value;             }         }         // Specifies the SOAP Extension to use with this method         public override System.Type ExtensionType         {             get {                 return typeof(BugService.SoapDisplayExtension);             }         }     } } 
  13. Add the following Web method's declaration in the BugService.asmx.cs class:

     [WebMethod, SoapDisplayExtension] public Bug GetBug(int bugID) {     Bug b = new Bug(bugID);     return b; } 
  14. Build Example6_1.

graphics/alert_icon.gif

The SOAP extension attribute is applied to the Web method declaration in the proxy class to implement a client-side SOAP extension.


graphics/alert_icon.gif

One way of applying a SOAP extension to a Web service is by applying an appropriate attribute to a Web method (this technique is shown in the Example6_1 project). An alternative way of applying the SOAP extension is by modifying the XML configuration file for the project. Specifically, a soapExtensionTypes XML element must be added to the webServices section of the configuration file as shown here:

 <configuration>   <system.web>     <webServices>        <soapExtensionTypes>            <add type="Example6_1.SoapDisplayExtension,Example6_1"                priority="1" group="0" />        </soapExtensionTypes>     </webServices>  </system.web> </configuration> 



    Team-Fly    
    Top


    MCAD Developing XML Web Services and Server Components with Visual C#. NET and the. NET Framework Exam Cram 2 (Exam Cram 70-320)
    Managing Globally with Information Technology
    ISBN: 789728974
    EAN: 2147483647
    Year: 2002
    Pages: 179

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