Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 38 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
38
Dung lượng
261,89 KB
Nội dung
192 Table 6-11: Selected Properties, Methods, and Events of the SoapHttpClientProtocol Class Property Description group to use when connecting to the Web service. A connection group provides a mechanism for allowing multiple clients within the same application to share connections open to a given Web server. CookieContainer Used to access the cookies maintained by the proxy. Also provides a mechanism for setting cookies for a particular domain. Credentials Specifies authentication credentials that can be used to log into the Web server. The supported methods of authentication include Basic Authentication, Windows NT Challenge/Response, Kerberos, and Digest. PreAuthenticate Specifies whether the authentication credentials should be sent immediately or as a result of receiving a 401 access denied error. Proxy Contains the information necessary to connect to the proxy server. This includes the URL, port, and user name/domain/password. RequestEncoding Specifies the type of encoding that will be used when serializing the request message. The default is UTF-8. Timeout Specifies the period of time, in milliseconds, that a synchronous Web request has to complete before the request is aborted. The default is infinity (−1). Url Specifies the address of the Web service endpoint. UserAgent Specifies the value of the user agent header in the HTTP request. Method Description Abort Used to abort any asynchronous method calls that are currently executing. Discover Used to dynamically discover the location of the Web service via the DISCO file referenced by the Url property. Event Description Disposed Used to provide notification when the proxy has been disposed. Let’s step through the code generated by WSDL.exe to see how the proxy class is implemented: // // <autogenerated> // This code was generated by a tool. // Runtime Version: 1.0.xxxx.xx 193 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // </autogenerated> // // // This source code was auto generated by WSDL, Version=1.0.xxxx.xx. // WSDL.exe first generates comments that document the version of the runtime as well as the version of WSDL.exe that was used to create the proxy. If the proxy will be included within a code base that is released to production, you might also want to record the date and time that the WSDL was generated along with a copy of the WSDL document itself. The date and time can be recorded by promptly checking the file into a source code repository or by adding it as a comment to the generated file. The WSDL document can be obtained by WSDL.exe itself. You can accomplish this by using one of the optional command-line parameters I discuss later in this section. namespace BrokerageFirm { using System.Diagnostics; using System.Xml.Serialization; using System; using System.Web.Services.Protocols; using System.Web.Services; /// <remarks/> [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Web.Services.WebServiceBindingAttribute(Name="SecuritiesSoap ", Namespace="http://woodgrovebank.com/Securities")] [System.Xml.Serialization.SoapIncludeAttribute(typeof(SoapReceiptHea der))] [System.Xml.Serialization.SoapIncludeAttribute(typeof(SoapPaymentHea der))] public class Securities : System.Web.Services.Protocols. SoapHttpClientProtocol { public SoapPaymentHeader SoapPaymentHeaderValue; 194 public SoapReceiptHeader SoapReceiptHeaderValue; The Securities class is defined within the BrokerageFirm namespace. It is derived from the SoapHttpClientProtocol class. SoapHttpClientProtocol serves as the base class for all ASP.NET proxies and contains the implementation necessary to communicate with most HTTP-based Web services. The Securities class is also decorated with three attributes. The first is the WebServiceBinding attribute, which serves the exact same role on the client as it does on the Web service. This attribute allows you to formally reference a particular binding defined within another namespace. The two other attributes are SoapInclude attributes. They tell the XML Serializer to include the SoapPaymentHeaderValue and the SoapReceiptHeaderValue member variables within the SOAP message. /// <remarks/> public Securities() { string urlSetting = System.Configuration.ConfigurationSettings.AppSettings ["SecuritiesWebServiceUrl"]; if ((urlSetting != null)) { this.Url = urlSetting; } else { this.Url = "http://localhost/BrokerageFirm/Securities.asmx"; } } The constructor sets the object’s Url property to the value of the SecuritiesWebServiceUrl application configuration parameter defined in the application’s configuration file. If the value is not found, the Url property is set to the value contained within the HTTP extension element that defines the address of the endpoint within the WSDL document’s service definition. You should consider modifying the else logic to throw an exception instead of defaulting to a hard-coded value. This will make it easier to diagnose some problems within your application. For example, when you are trying to debug your application, it would be easy to overlook the fact that the SecuritiesWebServiceUri parameter is misspelled within your configuration file. (Did you catch the misspelling?) You might need to dynamically modify the Url property at run time. For example, the application might want to reissue its request to another server in the event of failure. The Url property is a publicly exposed read/write property, so it can be modified by the client at run time. You can also set the Url property to point to a DISCO file containing a reference to the targeted Web service. You can then call the Discover method to dynamically bind to the Web service contained within the DISCO file. I will cover DISCO files in more detail in Chapter 10. Within the proxy class definition, methods are defined for each of the operations exposed by the Web service. For each operation, three methods are defined. The first method definition 195 is for synchronously invoking the Web method, and the other two are used in combination to invoke the Web method asynchronously. Here is the synchronous definition for the InstantQuote method: [System.Web.Services.Protocols.SoapHeaderAttribute "SoapReceiptHeaderValue", Direction=System.Web.Services. Protocols.SoapHeaderDirection.Out)] [System.Web.Services.Protocols.SoapHeaderAttribute ("SoapPaymentHeaderValue")] /// <remarks/> [System.Web.Services.Protocols.SoapRpcMethodAttribute ("http://woodgrovebank.com/Securities/InstantQuote", RequestNamespace="http://woodgrovebank.com/Securities", ResponseNamespace="http://woodgrovebank.com/Securities")] public System.Double InstantQuote(string symbol, CurrencyType targetCurrency) { object[] results = this.Invoke("InstantQuote", new object[] { symbol, targetCurrency}); return ((System.Double)(results[0])); } The InstantQuote method is decorated with the SoapHeader, DebuggerStepThrough, and SoapRpcMethod attributes. The DebuggerStepThrough attribute is used by the Visual Studio .NET debugger. The Visual Studio .NET debugger will not stop within the method marked with this attribute. The SoapHeader and SoapRpcMethod attributes serve the same purpose as they do when applied to a Web method. The SoapHeader attribute indicates which member variable should be serialized into the header of the SOAP message. The SoapRpcMethod attribute indicates the encoding style and the format of the message as well as the value of the SOAP HTTPAction header. The signature of the method itself is composed of .NET types that match their XML counterparts described within the types section of the WSDL document. This wrapper method definition allows code written against the proxy to take full advantage of the features provided by the .NET platform. For example, if a client attempts to pass invalid parameters, such as passing two strings to the Add method instead of two integers, the compiler will generate errors at compile time. Developers using Visual Studio .NET will also have full IntelliSense capabilities when they write code against the proxy. The implementation of the InstantQuote method packages the parameters into an array of objects and calls the Invoke method. Because this method is publicly exposed, you can call it directly. However, using the method exposed by the WSDL.exe-generated proxy provides a more convenient and natural calling convention. In many circumstances, making a synchronous call to a Web method is not ideal. This is especially true for Web services accessed via the Internet, where quality and speed of the connection might be uncertain. This might also be true for Web services hosted within the walls of a corporate data center. For example, a Web service might be used to expose data 196 contained within a mainframe. A significant amount of initialization might need to be done to set up a connection to the mainframe, or the Web service might be accessed during times of peak load. The next two methods defined for the InstantQuote operation are BeginInstantQuote and EndInstantQuote. These methods are used to make an asynchronous call to the Securities Web service’s InstantQuote Web method: /// <remarks/> public System.IAsyncResult BeginInstantQuote(string symbol, CurrencyType targetCurrency, System.AsyncCallback callback, object asyncState) { return this.BeginInvoke("InstantQuote", new object[] {symbol, targetCurrency}, callback, asyncState); } /// <remarks/> public System.Double EndInstantQuote(System.IAsyncResult asyncResult) { object[] results = this.EndInvoke(asyncResult); return ((System.Double)(results[0])); } } By convention, the method used to invoke the asynchronous call is prefixed with Begin and the method used to retrieve the parameters returned by the Web service is prefixed with End. The implementation invok es the BeginInvoke and EndInvoke methods, respectively. The asynchronous methods are not decorated with attributes used to describe the formatting of the message. The methodName parameter contains the name of the method that the ASP.NET runtime will use to retrieve the formatting information. If the asynchronous message is decorated with any attributes such as SoapDocumentMethod, these attributes will be ignored. [System.Xml.Serialization.SoapTypeAttribute("SoapReceiptHeader", "http://woodgrovebank.com/Securities/encodedTypes")] public class SoapReceiptHeader : SoapHeader { public System.Double Amount; public int ReferenceNumber; } [System.Xml.Serialization.SoapTypeAttribute("SoapPaymentHeader", "http://woodgrovebank.com/Securities/encodedTypes")] public class SoapPaymentHeader : SoapHeader { 197 public string NameOnCard; public string CreditCardNumber; public CardType CreditCardType; public System.DateTime ExpirationDate; } [System.Xml.Serialization.SoapTypeAttribute("CardType", "http://woodgrovebank.com/Securities/encodedTypes")] public enum CardType { VISA, MC, AMX, DISCOVER, } [System.Xml.Serialization.SoapTypeAttribute("CurrencyType", "http://woodgrovebank.com/Securities/encodedTypes")] public enum CurrencyType { US_DOLLARS, UK_POUNDS, GE_DEUTSCHMARKS, } } Lastly WSDL.exe defines .NET counterparts to the Payment and Receipt SOAP headers as well as the CurrencyType and CardType enumerations. WSDL.exe uses the SoapType attribute to explicitly define type information used by the XML Serializer to map the .NET types to their XML Schema counterparts. The use of the proxy to make a synchronous method call is fairly trivial. The following example writes the price of a security passed as a command-line argument out to the console: 198 using System; using BrokerageFirm; class Application { public void Main(string[] args) { string symbol = args[0]; Securities securities = new Securities(); // Create and initialize the Payment header. SoapPaymentHeader paymentHeader = new SoapPaymentHeader(); paymentHeader.CreditCardNumber = "12345"; paymentHeader.ExpirationDate = DateTime.Today; paymentHeader.CreditCardType = CardType.VISA; securities.SoapPaymentHeaderValue = paymentHeader; Console.WriteLine("{0} = {1}", symbol, securities.InstantQuote(symbol, CurrencyType.US_DOLLARS)); } } Because the Payment header is required to be passed to the InstantQuote method, I create a new SoapPaymentHeader object. Then I initialize it and set it to the SoapPaymentHeaderValue property on the securities object. The proxy is responsible for serializing the SoapPaymentHeader object within the header of the SOAP request message. Invoking the InstantQuote Web met hod asynchronously involves a little more work. The following code is contained within a WinForm application. Let’s walk through an example. I will write a console application that uses the Securities Web service proxy to make an asynchronous method call: using System; using System.Web.Services.Protocols; using BrokerageFirm; namespace SecuritiesClient { class Application { static Securities securities = new Securities(); First I create a class that will contain the console application. Then I create a static instance of the Securities Web service proxy as a static member of the class. I do this because the static callback function that I will now define will need to access the proxy object: 199 static void Main(string[] args) { string symbol = args[0]; SoapPaymentHeader paymentHeader = new SoapPaymentHeader(); paymentHeader.CreditCardNumber = "12345"; paymentHeader.ExpirationDate = DateTime.Today; paymentHeader.CreditCardType = CardType.VISA; securities.SoapPaymentHeaderValue = paymentHeader; securities.BeginInstantQuote(symbol, CurrencyType.US_DOLLARS, new AsyncCallback(InstantQuoteCallback), symbol); System.Threading.Thread.Sleep(30000); Console.WriteLine("Terminating application."); } As you have learned, WSDL.exe will properly handle generating proxies for Web services that support headers. The generated proxy code will contain a class declaration for each header defined by the Web service. Depending on the direction of the header, instances of the header class can be either retrieved or set using an associated property defined by the proxy class for the Web service. By default, the property will have the same name as the class, with a prefix of Value. If the class declaration contains an XmlType attribute (discussed in Chapter 7), the property on the client will simply be the name given to the XML type. The proxy class will also perform client-side validation of the SOAP headers before sending the message to the server. For example, the proxy will throw a SoapException if SoapPaymentHeaderValue was set to null when the Web method was invoked. Within the Main function, a call is made to the BeginInstantQuote method. This method accepts two parameters in addition to the securities symbol and the target currency of the quote. I also pass an instance of the AsyncCallback delegate that serves as a reference to the InstantQuoteCallback method I will define shortly. This tells the Web service proxy to execute the InstantQuoteCallback method once the Web service returns. If there is no callback method that should be invoked, you can pass null for the value of the parameter. The fourth parameter is intended to pass state that should be associated with the method once the callback has been invoked. The parameter is of type object and therefore accepts an instance of any .NET type. In this case, I pass the symbol of the security for which I have requested the quote. public static void InstantQuoteCallback(IAsyncResult result) { // Obtain the results. double price = securities.EndInstantQuote(result); 200 // Obtain the additional state that was sent by // the call to BeginCallback. WebClientAsyncResult webResult = (WebClientAsyncResult)result; string symbol = (string)webResult.AsyncState; // Display the results within a message box. Console.WriteLine("{0} = {1}", symbol, price); } } } The InstantQuoteCallback method receives a reference to the IAsyncResult interface of an object of type WebClientAsyncResult. This parameter is then passed to the EndAdd method to obtain the return value of the Web method call. Next I obtain the additional state information from the AsyncState property—in this case, the symbol passed to the Add method. Finally the price of the security is written to the console. Cookies Proxies derived from SoapHttpClientProtocol fully support HTTP cookies. However, the proxies have cookies disabled by default. To enable cookie support, you must set the CookieContainer property on the proxy object to reference an instance of a CookieContainer object. Earlier in the chapter, I leveraged session state to configure the target currency. The client first sets the target currency by calling SetCurrency. Then the client calls InstantQuote to obtain the price of the security. Because the Web service relies on cookies to maintain session state, clients using this Web service need to explicitly enable cookies. The following code demonstrates how to enable session state: using System; using BrokerageFirm; using System.Net; class Application { public void Main(string[] args) { string symbol = args[0]; Securities securities = new Securities(); // Enable session state by creating a new cookie container. securities.CookieContainer = new CookieContainer(); 201 // Receive a quote on the requested security in UK pounds. securities.SetCurrency(CurrencyType.UK_POUNDS); Console.WriteLine("{0} = {1}", symbol, securities.InstantQuote(symbol)); } } Once the proxy object has gone out of scope, all cookie information will be invalid. This is perfectly acceptable in the above console application. However, this might not be ideal if you need to maintain the cookie information across instances of the proxy. In such cases, it is necessary to persist the cookie collection and associate it to the new proxy object. Summary ASP.NET provides a robust, feature-rich platform for easily creating and consuming Web services. For a V1 product, it is remarkably feature complete. An ASP.NET Web service is represented by an .asmx file hosted within an IIS Web application. The implementation of the Web service can be contained within the .asmx file or within a compiled DLL. If the code appears inline within the .asmx file, the ASP.NET runtime will automatically compile it the first time it is accessed. A Web service is defined by a standard public class declaration. Public methods defined within the class can be exposed by the Web service if you decorate the method with the WebMethod attribute. This attribute exposes properties that can be optionally set to control the behavior of the ASP.NET runtime. The class can also be decorated with the WebService attribute. All ASP.NET Web services expose a SOAP interface over HTTP. Depending on the complexity of the Web service’s interface, an ASP.NET Web service might also support HTTP GET and HTTP POST. The ASP.NET runtime will automatically map data contained within requests from the client and their corresponding responses to their corresponding .NET datatypes. The ASP.NET platform will automatically generate documentation for the Web service. A human-readable HTML version of the documentation can be obtained by calling the .asmx file with no parameters. A programmatic WSDL version of the documentation can be obtained by appending &wsdl to the URL that addresses the .asmx file. ASP.NET supports two distinct encoding styles, Document and RPC. Document is the default and is used primarily for document-based message exchanges between the client and the server. RPC is used primarily for procedure-based communication between the client and the server. You can select RPC by using the SoapRpcService or SoapRpcMethod attribute. You should be careful when you pass value types as parameters because the ASP.NET platform has some inconsistencies when identity is maintained. The identities of built-in value types such as int and double are never maintained, even when passed by reference. The identity of a custom value type when passed by reference is maintained when the encoding style is set to RPC. However, the identity of custom value types passed by value is improperly maintained when the encoding style is set to RPC. Regardless of the style of encoding, SOAP formally defines how errors returned to the client should be encoded within a SOAP message. The ASP.NET runtime will automatically map [...]... developers in the future The signature of the IXmlSerializable interface is as follows: public interface IXmlSerializable { System .Xml. Schema.XmlSchema GetSchema(); void ReadXml(System .Xml. XmlReader reader); void WriteXml(System .Xml. XmlWriter writer); } The GetSchema method is called when the ASP.NET runtime generates the WSDL document for the Web service The ReadXml method is called when the SOAP message... how you can use ASP.NET to build and consume Web services In some respects, ASP.NET provides a more complete platform for building Web services than Remoting does For example, Remoting supports only RPC-style messages Microsoft is also hyping ASP.NET as the preferred platform for building Web services So when should you consider using Remoting instead of ASP.NET? Remoting vs ASP.NET You should consider... listen for incoming requests § Proxy The proxy object is responsible for receiving the method calls from the user Once a method call has been received, the proxy is responsible for eliciting the help of the appropriate formatter and transport to send the parameters to the remote object § Formatter The formatter is responsible for serializing the parameters into a format that can be shipped across the. .. field or property with the XmlAnyAttribute and XmlAnyElement attributes The XmlAnyAttribute attribute specifies that the parent element can contain any XML attribute in addition to the ones formally defined 217 within the schema The XmlAnyElement attribute specifies that the parent element can contain any XML element in addition to the ones formally defined within the schema The flexibility of open... null value You can also use the XmlRoot attribute to control the behavior of XML serialization Table 72 describes the properties exposed by the XmlRoot attribute Table 7-2: XmlRootAttribute Properties Property Description DataType Specifies the XML datatype in which the class should be encoded ElementName Specifies the name of the root XML element Form Specifies whether the XML element must be namespace... http://somedomain/MyWebService.asmx The schema for MyRecordSet would therefore be located at http://somedomain/MyWebService.asmx?MyRecordSet The URL that references the MyRecordSet schema is imported into the schema for the Web service itself Calls to this URL will return the schema produced by calling the WriteXmlSchema method exposed by the MyRecordSet class Summary XML serialization is responsible for serializing... Specifies the name of the XML element Form Specifies whether the XML element must be namespace qualified It is set to one of three values defined by the XmlSchemaForm enumeration: None, Qualified, or Unqualified IsNullable Specifies whether the value of the XML element can have its xsi:nil attribute set to true Namespace Specifies the XML namespace in which the element is defined Type Specifies the NET... Specifies the name of the XML element Form Specifies whether the XML element must be namespace qualified It is set to one of three values defined by the XmlSchemaForm enumeration: None, Qualified, or Unqualified IsNullable Specifies whether the value of the XML element can have its xsi:nil attribute set to true Namespace Specifies the XML namespace in which the element is defined Type Specifies the NET... But the standard convention for public properties and fields exposed by a NET type is Pascal case, in which the first letter of each word making up the entity name is uppercase By default, the name of the attribute in the serialized XML document is the name of the property or field Because the name of the field does not match the name of the attribute, I pass the intended name of the attribute to the. .. AttributeName Specifies the name of the XML attribute DataType Specifies the XML Schema built-in datatype in which the property or field should be encoded Form Specifies whether the XML attribute must be namespace qualified It is set to one of three values defined by the XmlSchemaForm enumeration: None, Qualified, or Unqualified Namespace Specifies the XML namespace in which the attribute is defined The Currency . behavior of the ASP .NET runtime. The class can also be decorated with the WebService attribute. All ASP .NET Web services expose a SOAP interface over HTTP. Depending on the complexity of the Web service’s. String .NET type, but the client can pass non-numeric data to the Web service. Therefore, it is up to the Web service to enforce additional constraints over and above what is provided by the .NET. especially true for Web services accessed via the Internet, where quality and speed of the connection might be uncertain. This might also be true for Web services hosted within the walls of a