Use Web Services Enhancements to send SOAP messages with attachments
Jeannine Hall GaileyWeb Consultant February 2003 applies to: Microsoft® ASP.NET WebMethodsWeb Services Enhancements 1.0 for Microsoft® .NETWS-Attachments specification DIME specification Microsoft® SOAP Toolkit 3.0 Abstract: Web Services Enhancements 1.0 for Microsoft .NET supports the use and DIME WS-Attachments specification to send attachments. table of Contents
Introduction Using DIME and Web Services Enhancements WSE's advanced DIME support for DIME When using WSE, the problem is a recommended Web service standard, which can use the DIME message package protocol to help send attachments in the SOAP message. This article describes the WEB Services Enhancements (WSE) 1.0 for Microsoft .NET supports the use of DIME and WS-ATTACHMENTS specifications to send attachments. Introduction WS-Attachments specifies a method of using direct Internet Messaging (DIME) to send and receives an attachment to SOAP messages, the form of attachments can be binary files, XML pieces, but also other SOAP messages. The DIME is used to encapsulate SOAP messages with MIME, based on Microsoft and IBMs. Like SOAP, DIME messages can be sent using standard transport protocols such as HTTP, TCP, and UDP. DIME supports streaming of data. DIME can even be used without SOAP, but the ability of DIME description message content will be affected. Microsoft supports DIME and WS-ATTACHMENTS in the first edition of Web Services Enhancements (WSE) to develop secure, stable, and scalable web services using Microsoft .NET. This article mainly discusses the implementation of DIME rather than the agreement itself. For further discussion about the DIME protocol, see the article I wrote in the MDSN Magazine in the MDSN Magazine (English). DIME is not strictly requiring to use with SOAP. DIME's driving force is mainly to transmit an accessory of SOAP messages more efficiently, which is especially useful for web services that need to include large binary files such as media files or binary data files. Of course, there is no DIME or you can send data in the SOAP message. For example, if you want to send a large media file to the client to the requesting request in the SOAP message, these binary attachments can be encoded as Base64 XML and they are included in the body of the SOAP message. However, when the attachment is very large, it is quite inconvenient to process; if a digital signature is performed, it may not be possible. Similarly, the situation will become very complicated when sending the encoding mode different from other SOAP messages of the primary SOAP message, XML document, or XML piece. In some cases, it is important to attach binary data to SOAP messages. Optimize DIME to be used with SOAP messages. Relying on metadata that already exists in the SOAP message, the DIME analyzer does not need to read a large amount of metadata from the DIME message itself, thereby alleviating the burden. This makes DIME messages faster, higher efficiency. For more information on DIME is better than MIME, see the article under Matt Powell UNDERSTANDING DIME AND WS-ATTACHMENTS. What is Web Services Enhancements? In order to implement the interoperability in the enterprise, the main supplier of XML Web Service (including Microsoft, IBM and VeriSIGN) proposes new specifications to improve critical web services (such as security, and messaging reliability) Interoperability of the accessory).
To support these new standards, Microsoft released Web Services Enhancements (WSE) 1.0, which includes a set of classes for implementing these new protocols and a set of filters provided by Microsoft ASP.NET, which are used to intercept Into and the SOAP message, as well as explaining or generating a SOAP header to support the desired function. WSE 1.0 supports the following specifications:
WS-Security Web Services Security Addendum Dime WS-Attachments WS-Routing WS-Referral For more information, see Web Services Enhancements for Microsoft .NET (English). Using DIME WSE V1.0 in Web Services Enhancements uses ASP.NET to support DIME with SOAP attachments, and you can read DIME messages from I / O streams or write DIME messages to I / O streams. This section describes the detailed process of adding binary attachments to the SOAP message in ASP.NET, followed by discussing the support of the WSE on the DIME stream. WSE runtime implementation DIME method For SOAP messages with attachments, a DIME-compatible message analyzer is implemented when the WSE is run, and the record of incoming DIME messages is converted, and extracts the primary SOAP from the first DIME record. The message is extracted from the subsequent accessory object record. When the primary SOAP message is extracted from the DIME, it is passed to the WSE message pipe, and is processed by a series of input filters to other headers supported by WSE. The figure below shows the method of processing incoming DIME messages when WSE runtime and ASP.NET. Figure 1: WSE runtime and ASP.NET process incoming DIME messages For outbound SOAP response messages with attachments, the DIME message analyzer in WSE builds a new DIME message, where the first DIME record is out of the station SOAP In response, all specified attachments are packaged in subsequent DIME records. The figure below shows the method of assembling the DIME message at the WSE runtime. Figure 2: WSE Runtime Assembly DIME Message WSE Run through a rich API to program control and support DIME. Microsoft.Web.Services.dime Namespaces Support DIME. For SOAP-based web services provided by ASP.NET, the SOAPCONText class in Microsoft.Web.Services namespace controls the behavior of the WSE runtime by specifying the use and properties of a given SOAP message. In the WSE programming model, a HTTPSoAPContext object is generated for the received request when the SOAP request information is received. HttpSoAPContext.RequestContext Attribute Accesses the SOAPCONTEXT object for the message and enumerate information in the WSE dedicated header element of the message. If the incoming DIME message is in line with the WS-Attachments specification, the WSE runs them as an accessory's SOAP message and extracts the primary SOAP message and all its accessories. For each attachment, you will add a DimeAtTachmentCollection to DimeAtTachmentCollections so that you can access these attachments via the SOAPCONText.attachments property. Similarly, attachments can be added to the DimeAtTachmentCollection of the SOAPContext object of the outgoing message, so that they are included in the DIME records of the message when the WSE is run. Next, let's take a look at the process of creating a DIME message with an attachment as a Web service response. Configuring Web Services Enhancements for DIME To use an attachment in DIME, even if WSE is installed on the ASP.NET web server, there is still a need for some additional DIME-related configurations for ASP.NET applications.
After creating a new ASP.NET Web service item in Microsoft® Visual Studio® .NET, you need to add a reference to Microsoft.Web.Services.dll assembly to the project. Also add a new type to the SOAPEXTensionTypes element, the method adds an Add element to the project in the web.config file, as shown below:
...
"Microsoft.Web.Services.WebserviceSextension, Microsoft.Web.Services, Version = 1.0.0.0, Culture = neutral, PublickeyToken = 31BF3856AD364E35 priority = "1" group = "0" /> soapextensiontypes> WebServices> configure> In this example, the TYPE attribute value cannot contain a separator or space. If WebServices and soapextensionTypes elements do not exist, they must also add them to the web.config file. WSE Settings Tools are an unsupported Visual Studio add-in, which can be easily configured to use WSE's Web service items. By installing the tool, you can easily configure the WSE-based project to use DIME. Adding an attachment to the SOAP message using WSE assumes that there is a web service class called ImageDimeService, which has a public method that returns a binary JPEG image file. In the content page of the service .aspx file, you should create an alias for these namespaces using the USING instruction, as follows: use system.Web.Services USING Microsoft.Web.Services Using Microsoft.Web.Services.Dime In this example, the ImageDimeService class is defined as follows: [WebSpace (Namespace = "http://example.com/dime/", Description = "Web service uses DIME to return one or more JPEG files.")]] Public class imageservice: System.Web.Services.WebService { ... The following GetImage method implements WebMethod, returns the requested JPEG file: [WebMethod] Public void getimage (string "iMageNameCollection) { // Get SOAPCONTEXT as a response message SOAPCONTEXT mycontext = httpsoapcontext.responsecontext; // Create an array for returning the URI of the associated DIME attachment. String [] returi = new string [imagenamecollection.length]; INT i = 0; // iterator / / Each file specified by the value in the imageID array // Create a DimeAtTachment object. FOREACH (STRING IMAGENAME IN ImagenameCollection) { // String, indicating the file name and path of the attachment. String filepath = "c: // images //" imagename ".jpg"; // Use the file name to create a new DIME attachment, // and pass MIME Media Type Image / JPEG // to specify attachment code. Dimeattachment DimeImage = New Dimeattachment "image / jpeg", typeformatenum.mediatype, FilePath); / / Generate the GUID-based URI reference to the attachment object, / / And assign it to the ID attribute recorded by the DIME. DimeImage.id = "URI:" Guid.newguid (). TOSTRING (); // Add the new DimeAtTachment object to the SOAPCONTEXT object. MyContext.attachments.add (DimeImage); // Add the generated URI to the returned array. Returi [I] = dimeiMage.ID; i ; } / / Return the URI that matches the ID value of the attachment // array. Return Returi; } In the WebMethod method, the SOAP request message issued from the client contains a set of image names. For each name in the collection, Web services retrieve associated JPEG files from the C: / Images folder and add images to the DimeAtTachmentCollection of ResponseContext. When WebMethod returns, the WSE is run as a main DIME record, and each dimattachment is the same as a subsequent record, which is the same as they are added to the DimeAtTachmentCollection. Extracting the Attachment from the DIME message Adding a client application using a web service and processes the DIME message, the client must also install WSE. To make the Microsoft .NET client application in Visual Studio support WSE DIME, you must add a reference to the Microsoft.Web.Services.dll assembly. In addition, after adding a web reference to DIME-based Web services, you must modify the proxy class in the References.cs file to inherit from Microsoft.Web.Services.WebServicesClientProtocol class in WSE. For example, the client web service agent of the IMAGESERVICE web service generated in the above example needs to modify as follows: Public Class ImageService: Microsoft.Web.Services.WebServicesClientProtocol If the client has already installed a WSE setting tool, the Add Web Reference will automatically generate a separate, proxy class ending with "WSE", which is inherited from the corresponding WSE class. In this case, use ImageServiceWSe as a service agent. The following example shows a method of retrieving multiple JPEG files as a DIME accessory using the ImageService Web service. Try { // Call the web method to transfer the image name, / / Capture the URI value from the returned array, // to reference an attachment by ID. String [] returi = myservice.getimage (imagenamecollection); } Catch (Exception EX) { // Handle any exception errors. } // Check if the response message contains any attachments. IF (MyService.ResponseSoApContext.attachments.count> 0) { // Display each additional JPEG image file. For (int i = 0; i { // convert the additional image into a new bitmap object for display. Bitmap MyImage = New Bitmap (MyService.ResponseSoAppContext.attachments [i] .stream); // Do some operations on the image. } // WARNING if no image is returned. MessageBox ("No images were returned"; } In this example, use the DimeAtTachment.Stream property to write each JPEG attachment as a data stream from memory to a new bitmap object. The advanced DIME support WSE can easily package attachments to the outgoing message, while WSE supports DIME support, this section discusses these functions. Put the big attachment is as you can write in the DIME article in MSDN Magazine, the DIME specification supports the large attachment into multiple records, which is very useful for processing super large accessories. The principle of the block is to divide the large attachment into blocks so that when the attachment is written to a single DIME record, it is not necessary to put the entire attachment into the buffer. WSE allows you to specify the block size of the attachment in bytes in bytes using the dimeattachment.chunksize property. However, since ASP.NET WebMethods do not support flow, the entire DIME message is cached in memory when using WSE in ASP.NET, which limits the validity of the block. A better way to use DIME transmission large attachments is to flow through the appropriate transmission method. Data flowing using DIMEREADER and DIMEWRITER DIME is a message-based format, and the DIME record is serialized and can be subjected to efficient use of data package level transport protocols such as TCP and UDP. WSE 1.0 supports two-way stream processing between the DIME message and System.io.Stream objects (such as NetworkStream), not limited by message-based protocols such as HTTP. When processing is used as a DIME stream, the WSE is running the DIME to which the DIME is running, so that there is no need to define the size of the object being performed. When the flow end is reached, the last record block is written. The following example generates an input stream from a file (such as a large binary image file), writes the stream into a series of block DIME records, and writes the DIME message into a Stream object, this object can be transmitted by TCP. NetworkStream: // Convert binary input stream to specify the MIME media type // DIME stream. Static void WriteTodime (Stream InputStr, String MediaType) { // Create a write device to write the DIME message to DimeStream DIMEWRITER MYDW = New Dimewriter (DIMESTR); // Create a GUID, used as a DIME record ID. Guid guid = guid.newguid (); String id = string.format ("uuid: {0}", guid.toString ()); // Create a new DIME record, its MIME media type // MediaType specifies and specifies the block with the contentLength value -1. DimeRecord myRecord = mydw.lastRecord (ID, MediaType, TypeFormatenum.mediatype, -1); / / Specify a small record block: 4KB. MyRecord.chunksize = 4096; // Write the stream into DimeRecord using binarywriter. BinaryWriter MyWriter = New BinaryWriter (MyRecord.Bodystream); // Write the contents of the incoming stream to binaryWriter. INT size = 4096; Byte [] bytes = new byte [4096]; INT Numbytes; While ((NumBytes = INPUTSTR.READ (Bytes, 0, Size)> 0) { MyWriter.write (bytes, 0, numbytes); } // Clean up Mydw.close (); } It is worth noting that SOAP-based DIME implementation is to read the entire DIME message into memory, and when DIME is flowing, you can use DIMERECORD.CHUNKSIZE to limit the amount of memory you need to use. The following method implements the opposite process, i.e. read the DIME stream, and extracts the recording content into the binary stream. Static void ReadFromDime (Stream DIMESTR) STREAM OUTSTR { // Create a reader for reading the streaming DIME message. DIMEREADER MyDR = New DimeReader (DIMESTR); // Create DimeRecord so that (only) read the current DIME record. DimeRecord myRecord = mydr.readrecord (); // Create a reader to read the recorded content. BinaryReader MyReader = New BinaryReader (MyRecord.Bodystream); // Write the content to the output stream. INT size = 4096; Byte [] bytes = new byte [4096]; INT Numbytes; While ((NumBytes = MyReader.Read (bytes, 0, size)> 0) { Outstr.write (bytes, 0, numbytes); } // Clean up MyReader.Close (); Mydr.close (); } Like the issues of DIME and 1.0 edition, WSE has some restrictions on the method of supporting DIME, WS-ATTACHMENTS, and related specifications. These issues include: Protection Accessories According to WS-Security Specifications (English), WSE provides comprehensive support to protect SOAP messages, but is not protected for SOAP message attachments sent in DIME messages. If you tell WSE to sign and encrypt the primary SOAP message, the SOAP message will be transmitted via WSE SecurityoutputFilter and give appropriate protection during this process. The SOAP message can only be packaged into an accessory's DIME message, which is not protected by any DIME analyzer because the attachment itself is not protected because the attachment itself is not protected. If an attachment in the DIME message is required, an encryption mechanism supported by a .NET framework should be used, which is provided by System.Security.cryptography namespace. Further, since the current DIME specification does not define a method of signing the DIME message header, WSE cannot determine if the DIME message is tampered with. Especially when using HREF to represent a specific accessory ID, WSE itself cannot verify that someone has modified the ID or a reference to a completely different place. Therefore, when using DIME to transmit sensitive data, it should always be protected or used safely. Reference Annex WSE supports the ID field of the DIME record, you can use the DimeAtTachment.id property to set this field. It allows you to assign and access attachments with a friendly ID string value instead of an integer index value. For example, by specifying [TOM "] instead of array index [0], you can access accessories of TOM, as shown below: MyService.ResponseSoAPContext.attachment [" Tom "]