Attach Docs to SOAP Messages

Send binary data from Web services with the WSE.

Dan Wahlin

October 30, 2009

10 Min Read
ITPro Today logo

XtremeData

LANGUAGES: C#

TECHNOLOGIES: WSE | SOAP | DIME | GDI+

 

Attach Docs to SOAP Messages

Send binary data from Web services with the WSE.

 

By Dan Wahlin

 

Web services are constantly evolving to support more andmore advanced requirements. Fortunately, new tools are emerging to helpsimplify the development of Web services and make them more efficient in theprocess. In this article, I'll introduce you to one new and exciting Webservice technology relating to a specification referred to as WS-Attachments.

 

Consider a Web service that returns a binary image, suchas a JPEG. Because the returned data is binary, it doesn't make much sense to"serialize" it into a SOAP message. The WS-Attachments specification wascreated for just that reason. Supported by Microsoft's Web Service Enhancements(WSE), the WS-Attachments specification instead allows a SOAP message toreference an image (or other document). This reduces the processor's overheadbecause it doesn't have to convert binary data to encoded bytes, thusminimizing the size of the SOAP messages. (For more on WSE, see the sidebar,"Web Service Enhancements.")

 

In a nutshell, the WS-Attachments specification defineshow you can "attach" documents and files to a SOAP message as opposed toembedding them directly within the body of one. This is possible byencapsulating the SOAP message and document using a technology named DirectInternet Message Encapsulation (DIME).

 

Build a Charting Web Service

To see WS-Attachments and the WSE in action, let's take alook at how to create a Web service capable of generating on-the-fly bar andline charts. This service accepts an XML document containing data points to addto the chart and returns a png image as a SOAP attachment (the service alsocould return other image types). Figure 1 shows an example of a bar chartreturned from the charting Web service.

 


Figure 1. The charting Web service parses XML data and is used alongwith GDI+ classes in .NET to create a bar chart.

 

The XML document that was sent to the Web service and usedto create the bar chart in Figure 1 is shown in Figure 2.You'll notice bylooking through the different elements and attributes that the document marksup point data the Web service should graph.

 

    width="500"graphTitle="Golf Scores">                                   

Figure 2. This simple XML document defines the size ofthe image, what type of chart should be generated, and the data to be graphed.The client sends the XML in a SOAP message to the charting Web service.

 

The charting Web service relies on a custom C# class namedChartGenerator to parse the XML shown in Figure 2. ChartGenerator has severaldifferent methods that handle extracting data from the XML document and drawinglines, text, and individual bars. Figure 3 shows ChartGenerator's only publicmethod, GenerateChart (you can download the entire ChartGenerator class).

 

public Stream GenerateChart() {

    //Get height and widthof chart

    XmlElement root =(XmlElement)this.DataSource;

    _ChartSize =

      newSizeF(float.Parse(root.GetAttribute("width")),

      float.Parse(root.GetAttribute("height")));

    int totalPoints = 0;

 

    //Find maximum valueof XML chart data

    this._MaxValue =GetMaxValue(out totalPoints);

    //Find number ofpoints in XML chart data

    this._TotalPoints =totalPoints;

 

    //Create a new Bitmapobject

    Bitmap b =

      new Bitmap((int)_ChartSize.Width,

       (int)_ChartSize.Height,

      PixelFormat.Format32bppArgb);

    //Create a graphicsdrawing surface

    _Graphics =Graphics.FromImage(b);

 

    //Set background colorto white

    _Graphics.Clear(Color.White);

    _Graphics.SmoothingMode= SmoothingMode.AntiAlias;

    _Graphics.TextRenderingHint =

      TextRenderingHint.AntiAlias;

    //Delegateresponsibility for drawing lines,

    //text, and bars tothe class's private methods

    DrawLines();

    DrawText();

    DrawBars();

 

    //Return a streamcontaining the image data

    //to the caller of themethod

    MemoryStream s = newMemoryStream();

    b.Save(s,ImageFormat.Png);

    return s;

}

Figure 3. The ChartGenerator class has several methodsthat draw the chart image. The Web service calls the GenerateChart() method tohandle the drawing of the chart.

 

GenerateChart creates the initial Bitmap object that willbe drawn upon by reading height and width data from the XML document shownearlier. It also discovers the maximum value of the XML data points, determinesthe total number of data points, and creates a Graphics object used to drawupon the Bitmap. Once these activities are complete, lines, text, and bars aredrawn by calling three private methods: DrawLines, DrawText, and DrawBars.

 

After the image is complete, the GenerateChart methodreturns it as a MemoryStream object. The image could be saved to disk insteadof being returned as a stream, but by using a stream, the application willperform more efficiently because the file system won't have to be touched.Currently, the GenerateChart method returns a png image format; the code easilycan be modified, however, to return other formats such as JPEG or BMP.

 

Add DIME to Web Methods

Now that you're familiar with the ChartGenerator class andits GenerateChart method, let's see how to call it and attach the returnedimage stream to a SOAP message using the WSE. The first task is to modify theweb.config file. To integrate the WSE classes into the SOAP processingpipeline, you must add the configuration code in Figure 4 to web.config,between the start and end tags. Unless you add thisconfiguration code, the classes that handle document attachments will not workproperly.

 

  

        

           priority="1"group="0"/>    Figure 4. Although installing the WSE provides youwith access to many different extension classes, different types ofconfiguration entries must be added into the web.config file for these classesto be used within Web services. In the case of WS-Attachments functionality,the XML configuration code shown here must be added within the start and close tags.   After modifying web.config, the Microsoft.Web.Services andMicrosoft.Web.Services.Dime namespaces must be imported into the chart Webservice to use the WS-Attachments and DIME classes. A class namedDimeAttachment contains DIME-specific functionality. You can create aDimeAttachment instance by using one of several overloaded constructors (seeFigure 5).   public DimeAttachment();  public DimeAttachment(System.String,     TypeFormatEnum,System.IO.Stream);   public DimeAttachment(System.String,     TypeFormatEnum,System.String);   public DimeAttachment(System.String,     System.String, TypeFormatEnum,System.IO.Stream);   public DimeAttachment(System.String,     System.String,TypeFormatEnum, System.String); Figure 5. The DimeAttachment class has severaloverloaded constructors you can use to create an instance of the class. Thepath to the document to attach a stream containing the document data can bepassed to the constructor. See the WSE documentation for more details about theconstructor parameters.   Each constructor allows you to identify the type ofpayload (i.e., "image/jpeg" or "image/png") being loaded as an attachment aswell as its format. An enumeration named TypeFormatEnum represents the format,and it can have a value of AbsoluteUri, MediaType, None, Unchanged, or Unknown.This article's charting Web service uses a TypeFormatEnum value of MediaType.Aside from these parameters, you can load the source document to be attached bypassing in the path to the document or the stream that represents the document.   Associating a DimeAttachment class with a SOAP messagerequires access to the current SOAP context. Because the charting Web servicesends an attachment along with the SOAP Response message, the Response contextmust be accessed. You do this by calling the HttpSoapContext object'sResponseContext property (see Figure 6).   [WebMethod] public bool GenerateChartImage(XmlNode data) {  bool status = true;   try {    //Create instance ofcharting class    ChartGenerator gen =new ChartGenerator();    //Assign XML datapoints to DataSource property    gen.DataSource = data;     //Generate the chartimage    Stream s =gen.GenerateChart();      //Access the SOAPResponse context    SoapContext resp =HttpSoapContext.ResponseContext;     //Attach the chartimage (DIME encapsulation)     resp.Attachments.Add(      new DimeAttachment("image/png",         TypeFormatEnum.MediaType,s));     }  catch (Exception exp) {    status = false;   }  return status; }Figure 6. The GenerateChartImage() Web Method createsan instance of the ChartGenerator class, assigning the chart's data source,then calls its GenerateChart() method.   The GenerateChartImage Web Method calls the ChartGeneratorobject and adds the returned stream into a DimeAttachment object. Then, thisattachment is added to the current Response SOAP context's Attachments collection.Note that, with only a few lines of code, you can add a document as a SOAPattachment. Very nice!   Access SOAP Attachments The client of the charting Web service must perform threetasks to generate and return the chart. First, it must create an XML documentcontaining chart data points (refer to the XML document shown in Figure 2).Next, it must call the Web service's GenerateChartImage Web Method and pass theXML document as a parameter. This call is made through a Web service proxyobject. Note that the client proxy class must inherit from theMicrosoft.Web.Services.WebServicesClientProtocol class rather than the normalSystem.Web.Services.Protocols.SoapHttpClientProtocol class to use the WSEclasses. This change requires you to edit the proxy code manually. Finally, theclient must access the Response SOAP context, extract the image attachment, andeither save it to the file system or write it to the Response stream. Figure 7demonstrates how to perform these steps. Several comments have been added tohelp explain what the code is doing at each step.   Bitmap b = null; XmlDocument xmlDoc =new XmlDocument();  //1. XML loaded from text area. It could also be loaded//from a file or created dynamically. xmlDoc.LoadXml(this.txtChartData.Text);   //2. Call the Web Service through the proxyChartService.ChartServiceWebServiceProxy.ChartService  proxy = newChartService.ChartServiceWebServiceProxy.   ChartService();proxy.GenerateChartImage(xmlDoc);   //3. Ensure that an attachment was received and save it//either to a file or to the Response output streamif (proxy.ResponseSoapContext.Attachments.Count > 0) {  //Load chart imageattachment into Bitmap  b = new Bitmap(  proxy.ResponseSoapContext.Attachments[0].Stream);   MemoryStream s = newMemoryStream();  //Save to memorystream...necessary for png images  b.Save(s,ImageFormat.Png);   //Set content type  Response.ContentType ="image/png";   //Save stream data tothe Response stream  s.WriteTo(Response.OutputStream); }Figure 7. The Web service's client does not need toinstall any charting software to generate chart images. The client must havethe WSE classes installed, however, to use WS-Attachments/DIME functionality.   Figures 8 and 9 show additional types of chart images youcan generate by passing different XML data to the charting Web service.  
Figure 8. This image shows how to overlay a line chart on a bar chart.You accomplish this by setting the barChart and lineChart attribute values toTrue in the XML document that is sent to the Web service. 
Figure 9. You can generate line charts using the charting Web service bysetting the barChart attribute in the source XML document to False and thelineChart attribute to True.   The WSE makes implementing the WS-Attachmentsspecification extremely straightforward. As a result, different types ofdocuments - from images to PDFs to Word documents - can be exchanged betweenentities in a much more efficient manner compared to "serializing" thedocuments into the SOAP message. This technology opens up a whole new world forWeb services because clients with WS-Attachments capabilities can hit servicesthat return a wide variety of complex data without installing specializedsoftware.   You can run a live example of the charting Web service atthe following URL on the XML for ASP.NET Developers Web site: http://www.XMLforASP.NET/codeSection.aspx?csID=96.   The sample code referenced inthis article is available for download.   Dan Wahlin (a Microsoft Most Valuable Professional inASP.NET) is the president of Wahlin Consulting and founded the XML for ASP.NETDevelopers Web site (http://www.XMLforASP.NET), whichfocuses on using XML and Web Services in Microsoft's .NET platform. He also isa corporate trainer and speaker, and he teaches XML and ASP.NET trainingcourses around the United States. Dan co-authored Professional Windows DNA (Wrox) and ASP.NET Tips, Tutorials& Code (Sams), and he authored XML for ASP.NET Developers (Sams). E-mailDan at [email protected].   Learn More About DIME You can think of DIME as a wrapper around a SOAP messageand an associated document or file. For more information, you can find an article on thesubject at http://msdn.microsoft.com/webservices/default.aspx?pull=/library/en-us/dnwebsrv/html/DIMEWSAttch.asp.You also can read the full WS-Attachments specification at http://msdn.microsoft.com/webservices/understanding/gxa/default.aspx?pull=/library/en-us/dnglobspec/html/wsattachmentsindex.asp.   Web Service Enhancements Web Services started out as a very simple concept:Exchange data between two or more entities, using XML messages. With therelease of development platforms such as Microsoft's .NET Framework, thisinitial concept has become useful in many different scenarios.   Because of the growth of the Web Services technology andits rapid proliferation, though, it has been in need of new and improvedfeatures to handle a variety of tasks such as securing messages andauthenticating Web service callers. To accommodate this need, Microsoft hasreleased Web Service Enhancements (WSE), which lets you integrate such featuresinto Web services with only a minimal investment of time and effort.   In this article, I've dealt only with one specific area ofWSE - the new WS-Attachments specification - but Web Services has experiencedgrowth pains in other areas, as well. If you're interested in learning moreabout other WSE features that help address these growth pains, such asauthenticating Web service callers and encrypting SOAP messages, see PracticeSafe Web Services and ProtectYour Info.   Tell us what you think! Please send any comments aboutthis article to [email protected] include the article title and author.      

Read more about:

Microsoft
Sign up for the ITPro Today newsletter
Stay on top of the IT universe with commentary, news analysis, how-to's, and tips delivered to your inbox daily.

You May Also Like