Professional ASP.NET 2.0 XML phần 9 pot

60 310 0
Professional ASP.NET 2.0 XML phần 9 pot

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

Figure 13-7 Asynchronous Web Service Methods The previous section discussed how to call Web services asynchronously over HTTP using the client-side capabilities of the .NET Framework. This approach is an extremely useful way to make calls to a Web service without locking up your application or spawning a bunch of background threads. This section discusses asynchronous Web service methods that provide similar capabilities on the server side. When you invoke a normal, synchronous ASP.NET Web service method, the response for a synchronous Web method is sent when you return from the method. If it takes a relatively long period of time for a request to complete, then the thread that is processing the request will be in use until the method call is done. Unfortunately, most lengthy calls are due to something like a long database query, or perhaps a call to another Web service. For instance, if you make a Web service call across the Internet, the current thread waits for the Web service call to complete. The thread has to simply wait around doing nothing until it hears back from the Web service. In this case, if you can free up the thread to do other work while waiting for the Web service, you can increase the throughput of your application. Waiting threads can impact the performance of a Web service because they don’t do anything productive, such as servicing other requests. To overcome this problem, you need a way to be able to start a lengthy background process on a server, but return the current thread to the ASP.NET process pool. When the lengthy background process completes, you would like to have a callback function invoked so that you can finish processing the request and somehow signal the completion of the request to ASP.NET. This is exactly what ASP.NET offers through asynchronous Web methods. 454 Chapter 13 16_596772 ch13.qxd 12/13/05 11:20 PM Page 454 How Asynchronous Web Methods Work When you write a typical ASP.NET Web service using Web methods, Visual Studio simply compiles your code to create the assembly that will be called when requests for its Web methods are received. When your application is first launched, the ASMX handler reflects over your assembly to determine which Web methods are exposed. For normal, synchronous requests, it is simply a matter of finding which methods have a WebMethod attribute associated with them, and setting up the logic to call the right method based on the SOAPAction HTTP header. For asynchronous requests, during reflection the Web service handler looks for Web methods with a specific signature that differentiates the method as being asynchronous. In particular, it looks for a pair of methods that have the following rules: ❑ There is a BeginXXX and EndXXX Web method where XXX is any string that represents the name of the method you want to expose. ❑ The BeginXXX function returns an IAsyncResult interface and takes an AsyncCallback, and an object as its last two parameters, respectively. ❑ The EndXXX function takes as its only parameter an IAsyncResult interface. ❑ Both BeginXXX and EndXXX methods must be flagged with the WebMethod attribute. If the Web service handler finds two methods that meet all these requirements, it will expose the method XXX in its WSDL as if it were a normal Web method. The method will accept the parameters defined before the AsyncCallback parameter in the signature for BeginXXX as input, and it will return what is returned by the EndXXX function. So if you have a Web method whose synchronous declaration looks like the following: [WebMethod] public string SleepForSpecificDuration(int milliseconds) { } An asynchronous declaration will look like the following: [WebMethod] public IAsyncResult BeginSleepForSpecificDuration ( int milliseconds, AsyncCallback callback, object s) { } [WebMethod] public string EndSleepForSpecificDuration (IAsyncResult call) { } The WSDL for both synchronous and asynchronous methods will be the same. After the Web service handler reflects on an assembly and detects an asynchronous Web method, it must handle requests for that method differently than it handles synchronous requests. Instead of calling a simple method, it calls the BeginXXX method. It deserializes the incoming request into the parameters to be passed to the function — as it does for synchronous requests — but it also passes the pointer to an internal callback function as the AsyncCallback parameter to the BeginXXX method. 455 XML Web Services 16_596772 ch13.qxd 12/13/05 11:20 PM Page 455 Now that you have a general understanding of the asynchronous Web methods, Listing 13-20 shows an example implementation. Listing 13-20: Creating Asynchronous Web Service Methods using System; using System.Web; using System.Collections; using System.Web.Services; using System.Web.Services.Protocols; [WebService(Namespace = “http://tempuri.org/”)] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] public class AsyncWebService : System.Web.Services.WebService { public delegate string SleepForSpecificDurationAsyncStub(int milliseconds); public string SleepForSpecificDuration(int milliseconds) { System.Threading.Thread.Sleep(milliseconds); return “Completed”; } public class WebServiceState { public object PreviousState; public SleepForSpecificDurationAsyncStub AsyncStub; } [WebMethod] public IAsyncResult BeginSleepForSpecificDuration(int milliseconds, AsyncCallback callback, object s) { SleepForSpecificDurationAsyncStub stub = new SleepForSpecificDurationAsyncStub(SleepForSpecificDuration); WebServiceState state = new WebServiceState(); state.PreviousState = s; state.AsyncStub = stub; return stub.BeginInvoke(milliseconds, callback, state); } [System.Web.Services.WebMethod] public string EndSleepForSpecificDuration(IAsyncResult call) { WebServiceState state = (WebServiceState)call.AsyncState; return state.AsyncStub.EndInvoke(call); } } In Listing 13-20, after the Web service handler calls the BeginSleepForSpecificDuration() method, it will return the thread to the process thread pool so it can handle any other requests that are received. The HttpContext for the request will not be released yet. The ASMX handler will wait until the callback function that it passed to the BeginSleepForSpecificDuration() function is called for it to finish processing the request. After the callback function is called, the ASMX handler will call the EndSleep 456 Chapter 13 16_596772 ch13.qxd 12/13/05 11:20 PM Page 456 ForSpecificDuration() function so that your Web method can complete any processing it needs to perform, and the return data can be supplied that will be serialized into the SOAP response. Only when the response is sent after the EndSleepForSpecificDuration() function returns will the HttpContext for the request be released. Controlling XML Serialization Using IXmlSerializable In .NET V1.x, you had only limited control over how types were serialized using the XmlSerializer. You could attribute types at design time and you could also override those attributes with new values at runtime, but it was based on attributes and you never really had complete control over the serialization process. Now with the release of .NET 2.0, this is no longer true. The IXmlSerializable interface, which has been present in the .NET Framework since version 1.x (but meant only for internal use), is now available for general use, thereby providing you with the ability to have more control over the gen- erated schema and wire format. One change that has been introduced with the IXmlSerializable interface is that the GetSchema() method should no longer be used. Instead you should use a new attribute named XmlSchemaProvider to specify the static method that generates and inserts the schema in the XmlSchemaSet for the Web service. The ReadXml() method controls reading the serialized format and is handed an XmlReader to read from the stream and populate the type. The WriteXml() method controls writing the serialized format and is handed an XmlWriter to write out the data to the stream. Listing 13-21 shows the Customer class implementing the IXmlSerializable interface. Listing 13-21: Implementing IXmlSerializable Interface to Customize XML Serialization using System; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; [XmlSchemaProvider(“CreateCustomerSchema”)] public class Customer : IXmlSerializable { private string _firstName; private string _lastName; private string _address; public Customer() { An example where you might need this type of control is when streaming large amounts of data. To enable streaming of data, you have to turn off response buffer- ing and then chunk the data into discrete blocks of data demarcated with XML ele- ments. IXmlSerializable lets you control the schema for this chunking format and control the reading and writing of this data to the stream with the ReadXml() and WriteXml() methods. 457 XML Web Services 16_596772 ch13.qxd 12/13/05 11:20 PM Page 457 } public Customer(string firstName, string lastName, string address) { _firstName = firstName; _lastName = lastName; _address = address; } public static XmlQualifiedName CreateCustomerSchema(XmlSchemaSet set) { XmlSchema schema = new XmlSchema(); schema.Id = “Test”; schema.TargetNamespace = “urn:types-wrox-com”; XmlSchemaComplexType type = new XmlSchemaComplexType(); type.Name = “customerType”; XmlSchemaAttribute firstNameAttr = new XmlSchemaAttribute(); firstNameAttr.Name = “firstName”; type.Attributes.Add(firstNameAttr); XmlSchemaAttribute lastNameAttr = new XmlSchemaAttribute(); lastNameAttr.Name = “lastName”; type.Attributes.Add(lastNameAttr); XmlSchemaAttribute addressAttr = new XmlSchemaAttribute(); addressAttr.Name = “address”; type.Attributes.Add(addressAttr); XmlSchemaElement customerElement = new XmlSchemaElement(); customerElement.Name = “customer”; XmlQualifiedName name = new XmlQualifiedName(“customerType”, “urn:types-wrox-com”); customerElement.SchemaTypeName = name; schema.Items.Add(type); schema.Items.Add(customerElement); set.Add(schema); return name; } public XmlSchema GetSchema() { return (null); } public void WriteXml(XmlWriter writer) { writer.WriteStartElement(“customer”, “urn:wrox-com”); writer.WriteAttributeString(“firstName”, _firstName); writer.WriteAttributeString(“lastName”, _lastName); writer.WriteAttributeString(“address”, _address); writer.WriteEndElement(); } public void ReadXml(XmlReader reader) { 458 Chapter 13 16_596772 ch13.qxd 12/13/05 11:20 PM Page 458 XmlNodeType type = reader.MoveToContent(); if ((type == XmlNodeType.Element) && (reader.LocalName == “customer”)) { _firstName = reader[“firstName”]; _lastName = reader[“lastName”]; _address = reader[“address”]; } } public override string ToString() { return (string.Format(“Person [{0} {1}]”)); } } In Listing 13-21, the Customer class implements the IXmlSerializable interface and the read/write is implemented in ReadXml() and WriteXml() methods, respectively. Note that the Customer class is decorated with an XmlSchemaProvider attribute which states that the schema for the serialized form of Customer class will be provided by the CreateCustomerSchema() method. In the CreateCustomer Schema() method, you make up a schema each time and provide it back to the framework. With the Customer class in place, you should be able to use that class from a Web service as shown in Listing 13-22. Listing 13-22: Utilizing the Customer Class from a Web Service Method using System; using System.Web.Services; using System.Web.Services.Protocols; [WebService(Namespace = “http://tempuri.org/”)] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] public class CustomerService : System.Web.Services.WebService { public CustomerService () { } [WebMethod] public Customer GetCustomer() { Customer cust = new Customer(“Thiru”, “Thangarathinam”, “900 N Rural Road, Chandler, AZ”); return cust; } } In Listing 13-22, the GetCustomer() method simply creates an instance of the Customer object and returns it back to the caller. If you test this Web service method using the default Web service test harness, you should see an output similar to Figure 13-8. 459 XML Web Services 16_596772 ch13.qxd 12/13/05 11:20 PM Page 459 Figure 13-8 Using Schema Importer Extensions In the .NET Framework 2.0, there is a new namespace named System.Xml.Serialization.Advanced that supports advanced XML serialization and schema generation scenarios. Currently, this namespace contains the following types: ❑ SchemaImporterExtension — Allows you to customize the code generated from a WSDL document ❑ SchemaImporterExtensionCollection — Represents the collection of SchemaImporterExtension objects Schema importation occurs whenever a Web service proxy is produced through a tool such as the Add Web Reference dialog box found in Visual Studio, or by using the WSDL.exe. Schema importation also occurs when using the XML Schema Definition Tool ( Xsd.exe) to generate code from a specific XSD document. The SchemaImporterExtension Class The SchemaImporterExtension class allows you to modify the code generated when using any of the automated tools. For example, you may have an existing class that processes book orders on a system and you have an existing XSD document that supplies your orders. Using the SchemaImporter Extension class, you can instruct the automated tools to generate code that uses your class. To control the generation of the code, you must use the classes found in the System.CodeDom namespace. You need to go through the following steps to enable the proxy generation tools to use your extensions. 1. Create an implementation of the SchemaImporterExtension class. 2. Use the ImportSchemaType method to write code for the code generator. The method contains parameters that allow you to examine the intercepted XSD type and create CodeDOM objects that are used to generate the new CLR code. 460 Chapter 13 16_596772 ch13.qxd 12/13/05 11:20 PM Page 460 3. Optionally, use the ImportAnyElement() method to handle <xsd:any> elements found in the XSD document. 4. Optionally, use the ImportDefaultValue() method to examine default values found in the XSD document and return a different default value. 5. Compile your extension into a library. 6. Sign the assembly. 7. Install the assembly in the Global Assembly Cache (GAC). 8. Modify the machine.config file to include the extension. Now that you understand the steps, the next section examines the creation of a schema importer exten- sion class. Creating a Schema Importer Extension Class Creating a schema importer extension is pretty easy. You simply derive from SchemaImporterExtension and override the appropriate methods. In most cases, you will override the ImportSchemaType() method, which perform most of the heavy lifting. Listing 13-23 shows an example in action. Listing 13-23: Custom Schema Importer Extension for the Customer Class using System; using System.CodeDom; using System.CodeDom.Compiler; using System.Collections; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; using System.Xml.Serialization.Advanced; namespace SchemaImporterExtensionsLib { public sealed class CustomerSchemaImporterExtension : SchemaImporterExtension { public override string ImportSchemaType(string name, string ns, XmlSchemaObject context, XmlSchemas schemas, XmlSchemaImporter importer, CodeCompileUnit compileUnit, CodeNamespace mainNamespace, CodeGenerationOptions options, CodeDomProvider codeProvider) { if (name.Equals(“Customer”) && ns.Equals(“urn:wrox-com”)) { CodeTypeDeclaration customer = new CodeTypeDeclaration(“Customer”); mainNamespace.Types.Add(customer); CodeMemberField firstNameField = new CodeMemberField( new CodeTypeReference(typeof(string)),”_firstName”); customer.Members.Add(firstNameField); CodeMemberProperty firstNameProperty = new CodeMemberProperty(); firstNameProperty.Attributes = MemberAttributes.Public | MemberAttributes.Final; firstNameProperty.GetStatements.Add(new CodeMethodReturnStatement( new CodeFieldReferenceExpression(new 461 XML Web Services 16_596772 ch13.qxd 12/13/05 11:20 PM Page 461 CodeThisReferenceExpression(), “_firstName”))); firstNameProperty.Name = “FirstName”; firstNameProperty.SetStatements.Add(new CodeAssignStatement( new CodeFieldReferenceExpression(new CodeThisReferenceExpression(),”_firstName”), new CodePropertySetValueReferenceExpression())); firstNameProperty.Type = new CodeTypeReference(typeof(string)); customer.Members.Add(firstNameProperty); CodeMemberField lastNameField = new CodeMemberField( new CodeTypeReference(typeof(string)),”_lastName”); customer.Members.Add(lastNameField); CodeMemberProperty lastNameProperty = new CodeMemberProperty(); lastNameProperty.Attributes = MemberAttributes.Public | MemberAttributes.Final; lastNameProperty.GetStatements.Add(new CodeMethodReturnStatement( new CodeFieldReferenceExpression(new CodeThisReferenceExpression(),”_lastName”))); lastNameProperty.Name = “LastName”; lastNameProperty.SetStatements.Add(new CodeAssignStatement( new CodeFieldReferenceExpression(new CodeThisReferenceExpression(),”_lastName”), new CodePropertySetValueReferenceExpression())); lastNameProperty.Type = new CodeTypeReference(typeof(string)); customer.Members.Add(lastNameProperty); return “Customer”; } return null; } } } In this code example, you can see that the only type this extension can process is the element named Customer that resides in the namespace, “urn:wrox-com”. This means that whenever this schema importer extension finds a type it is responsible for generating custom code, it does so via the Code DOM provided by the .NET Framework. Changes to the machine.config File When a proxy generation tool is used to import a XML Schema, it uses the System.Xml.Serialization .XmlSchemaImporter class internally to process the schema elements found in the XML Schema docu- ment. When created, the XmlSchemaImporter class loads any schema importer extensions defined in the underlying configuration. In this instance, by default, all the schema importer extensions are registered in the machine.config file. The following declaration shows how a schema importer extension is registered in machine.config. <configuration> <system.xml.serialization> <schemaImporterExtensions> <add name=”CustomerSchemaExtension” type=”SchemaImporterExtensionsLib.CustomerSchemaImporterExtension, 462 Chapter 13 16_596772 ch13.qxd 12/13/05 11:20 PM Page 462 SchemaImporterExtensionsLib, Version=1.0.0.0, Culture=neutral,PublicKeyToken=2489eb64bbbf6741” /> </schemaImporterExtensions> </system.xml.serialization> </configuration> After the extension is registered in the machine.config file, whenever a proxy generation tool encounters the type urn:wrox-com:Customer, the custom code (through the ImportSchemaType() method) will be added to the generated class file. Miscellaneous Web Service Features in .NET Framework 2.0 .NET Framework 2.0 provides a number of new features for the Web service developers. Some, which you have already seen, are the support for WS-I Basic Profile, custom XML serialization through IXmlSerializable interface, and schema importer extensions. In addition to these features, there are a couple of minor but important features that deserve a mention. The next few sections give you a run- down of these features. Enabling Decompression in a Web Service Client Now with .NET 2.0, enabling decompression on the client side just requires one line of code. All you need to do is to set the EnableDecompression property on an instance of a client proxy class to true, as follows. CategoriesService obj = new CategoriesService(); obj.EnableDecompression = true; This gives the Web clients the capability to interoperate with services that support compression. To dis- able decompression, set EnableDecompression to false. Setting this property to false enables the server to know that decompression is not supported on the client side. Type Sharing across Proxies ASP.NET Web services now support proxy type sharing. This feature allows you to share identical types from different Web services within the client-side proxy class. For example, you can take a type instance returned from one Web service and pass it to another, and vice versa. In many real-world scenarios, you may want to factor your application’s functionality into individual services that group methods that logically fit together. This typically leads to sharing one or more data types between those Web services. For example, you may have an Order Entry service that returns an Order object and an Order Status service that takes in an Order object. In this scenario, you can leverage Custom schema importer extension is useful when the client of a Web service has custom types that are much richer than those generated by wsdl.exe. Prior to the .NET Framework 2.0, this was possible only by modifying the generated proxy. But the problem with this approach was that the changes were lost when the proxy was regenerated. Schema Importer Extensions can now be developed and registered to map schema type to the custom type every time the proxy is generated. 463 XML Web Services 16_596772 ch13.qxd 12/13/05 11:20 PM Page 463 [...]... introduced with ASP.NET 2.0 ASP.NET 2.0 Configuration Management Now that you have a general understanding of the ASP.NET configuration architecture, the remainder of this chapter covers the configuration management functionalities of ASP.NET 2.0 The next section looks at the new configuration sections introduced with ASP.NET 2.0 467 Chapter 14 New Configuration Sections in ASP.NET 2.0 ASP.NET has added... CustomErrorsSection; XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(sect.SectionInformation.GetRawXml()); Response.Write(“Mode : “ + xmlDoc.DocumentElement.Attributes[“mode”].Value + “”); Response.Write(“DefaultRedirect : “ + xmlDoc.DocumentElement.Attributes[“defaultRedirect”].Value + “”); Response.Write(“Status Code =====> Redirect URLs ”); foreach (XmlNode node in xmlDoc.DocumentElement.ChildNodes)... } Retrieving Configuration Settings using Raw XML In this code, you get reference to the contents of the element by calling the GetRawXml() method of the SectionInformation object Load that raw XML into an XmlDocument object... process the raw XML through the properties and methods of the XmlDocument object In addition to reading the configuration settings in the form of raw XML, you can also update the configuration settings by invoking the SetRawXml() method of the SectionInformation object To this method, you supply the new XML string value as an argument 486 ASP.NET 2.0 Configuration For reasons of maintainability, ASP.NET applications... configuration section using raw XML ❑ How to create a custom configuration section and persist its contents onto a web.config file ❑ Built-in management tools supplied with ASP.NET 2.0 and Visual Studio 2005 The next section starts by exploring the ASP.NET configuration architecture Chapter 14 ASP.NET Configuration A web.config file is an XML- based text file that can contain standard XML document elements,... model, and so on; however ASP.NET 1.0 provided only basic support for configuration management, leaving Notepad pretty much the tool of choice for configuration management But now with the release of ASP.NET 2.0, things have dramatically changed with the suite of new configuration improvements that Web developers and administrators can take advantage of As part of this, ASP.NET 2.0 ships with a new configuration... leveraging sophisticated features such as SOAP headers, SOAP extensions, custom XML serialization, and schema importer extensions while building Web services Finally, the NET Framework 2.0 also offers new features such as enable decompression, type sharing across proxies, and support for SOAP 1.2 464 ASP.NET 2.0 Configuration When ASP.NET 1.0 was first released, it was lauded for the comprehensive feature... WebConfigurationManager.AppSettings[“shareLocation”]; Response.Write(“Retrieved value : “ + shareLocationFromConfig); //Code to connect to the share for file processing } Retrieving Configuration Settings from appSettings section This code... Person.ContactType”, conn); command.CommandType = CommandType.Text; SqlDataReader reader = command.ExecuteReader(); contactTypeView.DataSource = reader; contactTypeView.DataBind(); } } Retrieving Connection Strings from connectionStrings section ... utilized the WebConfigurationManager to programmatically retrieve the connection string In addition to the programmatic approach, ASP.NET 2.0 also provides a new declarative approach to retrieve configuration settings using “$” expressions These expressions are new in ASP.NET 2.0, and they allow you to load connection strings, resources, and other items using a declarative approach For example, you can . at the upper level are applied. 467 ASP. NET 2. 0 Configuration 17_ 596 7 72 ch14.qxd 12/ 13 /05 11 :08 PM Page 467 New Configuration Sections in ASP. NET 2. 0 ASP. NET has added a number of new configuration. 13-8. 4 59 XML Web Services 16_ 596 7 72 ch13.qxd 12/ 13 /05 11 : 20 PM Page 4 59 Figure 13-8 Using Schema Importer Extensions In the .NET Framework 2. 0, there is a new namespace named System .Xml. Serialization.Advanced that. exploring the ASP. NET configuration architecture. 17_ 596 7 72 ch14.qxd 12/ 13 /05 11 :08 PM Page 465 ASP. NET Configuration A web.config file is an XML- based text file that can contain standard XML document

Ngày đăng: 12/08/2014, 23:22

Từ khóa liên quan

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan