Web services enhancements (WSE) allows developers to incorporate security, routing, and attachments features into their Web services. WSE implementation has been based on an additional set of standards (known as the WS- series of standards, WS-Security, WS-Routing, WS-Attachments). For instance, currently Web services communication can be secured by sending a message over a secure transport such as SSL, but it works only for point-to-point communications. For instance, if a Web service is asynchronously accessed securely over a route A->B->C->D, the ultimate receiving service has to communicate with the sender to authenticate the sender of a SOAP message, which is not feasible in multiple scenarios. WS-Security allows the security credentials to be trusted by both sender and receivers. These security tokens are themselves placed in SOAP messages (using headers). After a Web server receives a SOAP request, it can verify the integrity of the security token without connecting back to a client's computer. Web services routing enables transparent delegation of the route that a SOAP message takes to an XML Web service. By using WSE, services can be designed so that the network topology is transparent to the client. An intermediate server can be configured to run as a WSE router. Clients then send SOAP messages to the router, which then delegates the SOAP messages to the server hosting the Web service. This can be used to individually take Web servers offline for maintenance without modifying any client code. All requests can be passed on to another computer using the referral cache XML configuration file in the Web services router.
So far you have seen standard XML messages passed using SOAP requests and responses. XML by definition doesn't allow binary data to be passed without modification. In many circumstances, it becomes essential to transmit binary data with SOAP messages apart from the regular XML data. WSE provides an implementation of DIME-based Web services attachments. Web Services Enhancements version 1.0 can be downloaded from Microsoft (http://msdn.microsoft.com/ webservices ). A newer developer preview release of the Web Services Enhancements (v 2.0) is also available from Microsoft (http://msdn.microsoft.com/webservices). This version has been used for the discussion in this book and will probably be generally released by the time you read this. Web Services Enhancements (WSE) implementation is available in the Microsoft.Web.Services assembly. This assembly must be referenced by appropriate applications and Web services that utilize the enhancements. For instance, if Web services is utilizing the enhancements, an entry must be made in the web.config file to refer to that assembly, in the <assemblies> section. Also, the SOAP extension types entry must be added in the <webServices> section. The WSE assembly must be added to the bin directory of the wwwroot as well.
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.web> <compilation> <assemblies> <add assembly="Microsoft.Web.Services"/> </assemblies> </compilation> <webServices> <soapExtensionTypes> <add type="Microsoft.Web.Services.WebServicesExtension, Microsoft.Web.Services, Version=2.0.0.0, Culture=neutral,PublicKeyToken=31bf3856ad364e35" priority="1" group="0" /> </soapExtensionTypes> </webServices> </system.web> </configuration> After the required configuration parameters are added, Web services can then be developed using the extensions. For instance, Listing 9.8 provides the complete development of a catalog service, which provides an rtf (Rich Text Format) based catalog to a Web service requestor . You can see the amount of simplification the WSE extensions have enabled. Listing 9.8 A Catalog DIME Service<%@ WebService Language="C#" Class="hks.CatalogService"%> using System; using System.Web; using System.Web.Services; using Microsoft.Web.Services; using Microsoft.Web.Services.Dime; namespace hks { [WebService(Namespace="http://www.hiteshseth.com/webservices")] public class CatalogService { [WebMethod(Description="Get Product Catalog")] public void GetProductCatalog(String itemCode) { SoapContext ctx = ResponseSoapContext.Current; DimeAttachment catalogAttach = new DimeAttachment("application/rtf", TypeFormatEnum.MediaType,@"C:\Catalogs\"+itemCode+".rtf"); ctx.Attachments.Add(catalogAttach); } } } After the Web service has been developed, a Windows application (or a Web application) can be developed to use the WSE extensions as well to appropriately receive the attachments (Figure 9.12). A minor modification is required, however, on the Web service stub (generated through the Add Web Reference dialog box). The stub should be a subclass of the Microsoft.Web.Services.WebServicesClientProtocol instead of the traditional System.Web.Services.Protocols.SoapHttpClientProtocol . namespace CatalogApplication.localhost { using System.Diagnostics; ... using Microsoft.Web.Services; ... public class CatalogService : WebServicesClientProtocol { ... } Figure 9.12. Using Web services with attachments to develop a distributed Product Catalog Reader application.
When the stub has been modified and compiled, the GUI (or a Web) application (Listing 9.9) can then appropriately utilize the Web service built using Web services extensions. Listing 9.9 Using a DIME-based Catalog Serviceusing System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data; using Microsoft.Web.Services; using System.IO; namespace CatalogApplication { public class CatalogForm : Form { private Label label1; private TextBox ItemCodeTextBox; private RichTextBox CatalogRTF; private Button GetCatalogButton; private System.ComponentModel.Container components = null; public CatalogForm() { InitializeComponent(); } protected override void Dispose( bool disposing ) { if( disposing ) { if (components != null) { components.Dispose(); } } base.Dispose( disposing ); } private void InitializeComponent() { this.label1 = new Label(); this.ItemCodeTextBox = new TextBox(); this.CatalogRTF = new RichTextBox(); this.GetCatalogButton = new Button(); this.SuspendLayout(); // // label1 // this.label1.Location = new System.Drawing.Point(8, 16); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(56, 16); this.label1.TabIndex = 0; this.label1.Text = "Item Code"; // // ItemCodeTextBox // this.ItemCodeTextBox.Anchor = ((AnchorStyles)(((AnchorStyles.Top AnchorStyles.Left) AnchorStyles.Right))); this.ItemCodeTextBox.Location = new System.Drawing.Point(72, 14); this.ItemCodeTextBox.Name = "ItemCodeTextBox"; this.ItemCodeTextBox.Size = new System.Drawing.Size(216, 20); this.ItemCodeTextBox.TabIndex = 1; this.ItemCodeTextBox.Text = "1"; // // CatalogRTF // this.CatalogRTF.Anchor = ((AnchorStyles)((((AnchorStyles.Top AnchorStyles.Bottom) AnchorStyles.Left) AnchorStyles.Right))); this.CatalogRTF.Location = new System.Drawing.Point(8, 48); this.CatalogRTF.Name = "CatalogRTF"; this.CatalogRTF.Size = new System.Drawing.Size(280, 184); this.CatalogRTF.TabIndex = 2; this.CatalogRTF.Text = ""; // // GetCatalogButton // this.GetCatalogButton.Anchor = ((AnchorStyles)((AnchorStyles.Bottom AnchorStyles.Right))); this.GetCatalogButton.Location = new System.Drawing.Point(200, 240); this.GetCatalogButton.Name = "GetCatalogButton"; this.GetCatalogButton.TabIndex = 3; this.GetCatalogButton.Text = "Get Catalog"; this.GetCatalogButton.Click += new System.EventHandler(this.GetCatalogButton_Click); // // CatalogForm // this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.ClientSize = new System.Drawing.Size(292, 273); this.Controls.Add(this.GetCatalogButton); this.Controls.Add(this.CatalogRTF); this.Controls.Add(this.ItemCodeTextBox); this.Controls.Add(this.label1); this.Name = "CatalogForm"; this.Text = "Catalog Reader Application"; this.ResumeLayout(false); } [STAThread] static void Main() { Application.Run(new CatalogForm()); } private void GetCatalogButton_Click(object sender, System.EventArgs e) { String itemcode = ItemCodeTextBox.Text; localhost.CatalogService proxy = new localhost.CatalogService(); proxy.GetProductCatalog(itemcode); if (proxy.ResponseSoapContext.Attachments.Count == 1) { StreamReader reader = new StreamReader(proxy.ResponseSoapContext.Attachments[0].Stream); CatalogRTF.Rtf = reader.ReadToEnd(); } } } } |