Asp.net|web|web Service Summary: This article explains how Microsoft's ASP.net Web Services Approach (WebMethod) provides an efficient way to build Web services. WebMethod can expose the traditional Microsoft. NET approach to Web service operations, supporting HTTP, XML, XML Schemas, SOAP, and WSDL. The WebMethod (. asmx) processing handler automatically passes the input SOAP message to the appropriate method and automatically serializes the input XML elements into the corresponding. NET object.
Introduced
Currently in Microsoft. There are two fundamentally different ways to implement HTTP based Web services in net. The bottom line is to write a custom IHttpHandler class that inserts the. NET HTTP pipeline. This approach requires that you use the System.Web API to process the HTTP messages you enter and use the System.Xml API to handle the SOAP encapsulation in the HTTP body. Writing a custom handler requires you to manually create a WSDL document that correctly describes the implementation. Strictly performing all of these operations requires that you have a good understanding of XML, XSD, SOAP, and WSDL specifications, but this is difficult for most developers.
A more efficient way to implement Web services is to use the Microsoft ASP.net webmethods framework component. Asp. NET publishes a specific IHttpHandler class for. asmx endpoints (called Webservicehandler), which provides the necessary template files for XML, XSD, SOAP, and WSDL features. Because the WebMethods framework component frees you from the complexities of the underlying XML technology, you can quickly focus on the business issues at hand.
Figure 1: Tradeoff between flexibility and productivity
The choice between implementing technologies creates a trade-off between the flexibility and productivity shown in Figure 1. Writing a custom IHttpHandler gives you unlimited flexibility, but it takes you a long time to write, test, and debug your code. The WebMethods framework component makes it easy to build your own Web services and run quickly, but it's clear that you are limited by the boundaries of the framework's components. However, you can extend the framework component by adding your own additional functionality when the WebMethods framework component does not provide the information you need completely.
Typically, unless you have mastered XML, XSD, SOAP, and WSDL and are willing to bear the burden of handling them directly, it is best not to focus on the WebMethods framework components required by the Web service. It provides the basic services required by most Web service endpoints (endpoints) and some interesting extensibility capabilities to "bend" the framework components to fit your precise needs. This article is based on this assumption to discuss the internal information of how WebMethods works. If you are not familiar with XML schemas and SOAP, you can see Understanding XML Schemas and Understanding soap.
WebMethods Framework Components
The WebMethods framework component loops through a method that maps a SOAP message to a. NET class. The implementation of this function first needs to annotate your method with the [WebMethod] attribute in the System.Web.Services namespace. For example, the following. NET class contains four methods, two of which use the [WebMethod] attribute annotation:
Using System.web.services;public class mathservice{ [WebMethod] public double Add (double x, double y) { return x + y; } [WebMethod] Public double subtract (double x, double y) {return x-y ; } Public double Multiply (double x, double y) {return x * y; } Public double Divide (double x, double y) {return x/y }}
In order to reuse this class in the WebMethods framework component, you need to compile the class into a part (assembly) and copy it to the bin directory of the virtual directory. In this example, the add and subtract methods can be exposed as Web service operations, but multiply and divide cannot (because they do not use [WebMethod] tags).
You can expose add and subtract to Web service operations through an. ASMX endpoint (endpoint). To do this, create a new text file named Math.asmx that contains the simple declaration below and place it in the virtual directory that contains the part (note: It enters the virtual directory instead of the subdirectory bin):
<%@ WebService class= "MathService"%>
This statement tells the. asmx handler which class is used to check webmethods, and the handler automatically processes other information. For example, assuming that the virtual directory is called "math" and that it contains math.asmx, and that the bin subdirectory contains the part, then browsing the http://localhost/math/math.asmx will cause the. asmx handler to generate the document page shown in Figure 2.
This is a great change from how the ASMX handler works. The. asmx file typically contains only webservice declarations that refer to the Web service class by name, as shown above. Therefore, in this case, the part must have been compiled and configured in the Bin directory of the virtual directory. The ASMX handler also provides Just-in-time (Just-in-time) Compilation of the source code in the. asmx file. For example, the following file (called Mathjit.asmx) contains the source code for the WebService declaration and the referenced class.
<@% WebService class= "Mathservicejit" language= "C #"%>using System.web.services;public class mathservicejit{ [WebMethod] public double Add (double x, double y) {return x + y; } [WebMethod] Public double subtract (double x, double y) {return x-y ; } Public double Multiply (double x, double y) {return x * y; } Public double Divide (double x, double y) {return x/y }}
When
accesses this file for the first time through HTTP, the. asmx handler compiles the source code and configures the part to the correct location. Note that the WebService declaration must provide a language so that the. asmx handler can select the correct compiler at run time. An obvious problem with this approach is that you will not find compilation errors until you first access the file.
Diagram 2:mathservice document
When you use Visual Studio. NET to create a new Web service project, it usually uses the "two-file" technique to separate the source file from the. asmx file that references it. The integrated development Environment (IDE) hides these files, but you can click Show All files on the Solution Explorer toolbar, and you will find that each Web service class in the project has two files. In fact, Visual Studio. NET does not support high brightness reminders or IntelliSense for. asmx files. After you have a Web project, Visual Studio. NET also handles the creation of virtual directories and automatically compiles the parts into the bin directory of the virtual directory.
before delving into how the. asmx handler works, let's briefly discuss how messages from IIS are assigned to the. asmx handler for processing. When an incoming HTTP message arrives at Port 80, IIS uses its own metabase (metabase) information to find out which ISAPI DLL to use to process the message. NET installer maps an. asmx extension to Aspnet_isapi.dll, as shown in Figure 3. The IIS application mappings for
Diagram 3:.asmx
Aspnet_isapi.dll are a standard ISAPI extension provided by the. NET Framework component, which simply forwards the HTTP request to a separate called aspnet_ Wp.exe in the process of working. aspnet_wp.exe hosted the common language Runtime and. NET HTTP pipelines. Once the message enters the. NET HTTP pipeline, the pipeline queries the configuration file to see which IHttpHandler class should be used to handle the given extension. If you look at the Machine.config file, you will find that it contains a httphandler mapping of the. asm file, as follows:
<configuration> <system.web>
There are two pieces of information in the HTTP message you enter that can be used to find out which method in the calling class: the SOAPAction header or the requested element name (for example, the element name within the Soap:body element). In this case, any one indicates the name of the method the sender wants to invoke.
By default. The ASMX handler uses the value of the SOAPAction header to perform message sending. Therefore, the. asmx handler looks at the SOAPAction header in the message, and then uses the. NET Reflection (Reflection) examines the methods in the referenced class. It only considers methods that are marked with the [WebMethod] flag, but it correctly determines which method to invoke by looking at the SOAPAction value of each method. Because we do not explicitly specify the value of SOAPAction in the method of our class, the. asmx handler assumes that the value of the SOAPAction is a combination of the method name followed by the name space of the Web service. Because we do not specify a namespace, the handler takes the http://tempuri.org as the default value. Therefore, the default SOAPAction value of the Add method is http://tempuri.org/Add.
You can use the [WebService] flag as the annotation for the class to customize the name space of the Web service, and use the [SoapDocumentMethod] flag described below as the webmethods annotation to specify the SOAPAction value:
Using system.web.services;using System.Web.Services.Protocols; [WebService (namespace= "Http://example.org/math")]public class mathservice{ [WebMethod] public double Add ( Double x, double y) {return x + y; } [WebMethod] [SoapDocumentMethod (action= "Urn:math:subtract")] Public double subtract (double x, double y) {return x-y ; } ...}
Now, the ASMX handler thinks that the value of the Add method's SOAPAction is HTTP://EXAMPLE.ORG/MATH/ADD (using the default heuristic), subtract the method is Urn:math: Subtract (because we explicitly define this value). For example, the following HTTP request message invokes the subtract operation:
Post/math/math.asmx Http/1.1host:localhostcontent-type:text/xml; Charset=utf-8content-length:lengthsoapaction: "Urn:math:subtract" <soap:envelope xmlns:soap= "http:// schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <subtract xmlns=" Http://example.org/math " > <x>33</x> <y>66</y> </Subtract> </soap:body></soap :envelope>
If the. asmx handler cannot find the SOAPAction of the HTTP message that matches the input, it simply throws an exception (which explains how the exception is handled). If you are unwilling to rely on SOAPAction head for method scheduling, you can instruct. The ASMX handler uses the name of the request element by using the Routingstyle property of the [SoapDocumentService] flag as the annotation of the class. If you do, you will probably also indicate that webmethods does not need soapaction values by setting the value of SOAPAction to an empty string:
Using system.web.services;using System.Web.Services.Protocols; [WebService (namespace= "Http://example.org/math")] [SoapDocumentService ( routingstyle=soapserviceroutingstyle.requestelement)]public class MathService{ [ WebMethod] [SoapDocumentMethod (action= ")] public double Add (double x, double y) {return x + y; } [WebMethod] [SoapDocumentMethod (action= "")] Public double subtract (double x, double y) {return x-y ; } ...}
In this case, the handler does not view the SOAPAction value-it replaces it with the name of the request element. For example, it thinks that the name of the request element of the Add method is add (from the Http://example.org/math namespace), and this HTTP request message is shown below:
post/math/math.asmx http/1.1host:localhostcontent-type:text/xml; charset=utf-8content-length:len Gthsoapaction: "" "<soap:envelope xmlns:soap=" http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> & Lt Add xmlns= "Http://example.org/math" > <x>33</x> <y>66</y> </Add> </soap:b Ody></soap:envelope>
Therefore, when an. asmx handler receives an input HTTP request, the first important thing is to find out how to send the message to the corresponding WebMethod. But before you can actually call the method, it needs to map the input XML to a. NET object.
Maps XML to an object
once the Webmehod handler finds out which method will be invoked, it then needs to convert the XML message to a. NET object that can be supplied to the method call. After the message is sent, the handler checks the class through reflection to find out how to handle the input XML message for this purpose. The XmlSerializer class in the System.Xml.Serialization namespace performs an automatic mapping between Xml and objects. The
XmlSerializer makes it possible for any public. NET type to be mapped to an XML schema type, and has a similar mapping that can be used in the. NET objects and XML instance documents (shown in Figure 4). The current XmlSerializer is limited to the model supported by the XML schema and therefore cannot handle all the complexities of the current modern object model (such as complex, non-tree object diagrams, dual pointers, and so on). However, XmlSerializer can handle most of the complex types that developers tend to use.
For the Add method shown in the previous example, XmlSerializer maps the x and Y elements to. NET double-precision values, so they can be used when the add is invoked. The Add method returns a double value to the caller, which then needs to serialize the value back to an XML element in the SOAP response.
Figure 4: Mapping XML to Objects
XmlSerializer can also automatically handle complex types (except for the limitations described above). For example, the following WebMethod calculates the distance between two point (points) structures.
Using system;using System.web.services;public class Point {public double X; public double Y;} [WebService (namespace= "Urn:geometry")]public class Geometry { [WebMethod] public double Distance (Point orig, Point Dest {return math.sqrt (Math.pow (Orig.x-dest.x, 2) + Math.pow (ORIG.Y-DEST.Y, 2)); }
The SOAP request message for this operation will contain a distance element containing two child elements, one called orig and the other dest, each containing two child elements x and Y, as follows:
<soap:envelope xmlns:soap= "http://schemas.xmlsoap.org/soap/envelope/" > <soap:Body> <distance xmlns= "Urn:geometry" > <orig> <x>0</x> <y>0</y> </orig> <dest> <x>3</x> <y>4</y> </dest> </Distance> </soap:Body></soap:Envelope>
In this case, the SOAP response message will contain a distanceresponse element that contains a distanceresult element of a double-precision type:
<soap:envelope xmlns:soap= "http://schemas.xmlsoap.org/soap/envelope/" > <soap:Body> <distanceresponse xmlns= "Urn:geometry" > <DistanceResult>5</DistanceResult> </ Distanceresponse> </soap:Body></soap:Envelope>
The default XML map uses the name of the method as the name of the request element, and the name of the parameter as the name of its child element. The structure of each parameter depends on the type's structure. The names of public fields and properties are simply mapped to child elements (in this case, X and y in point). By default, the name of the response element is followed by the name of the request element Plus "Response". The response element also contains a child element, the name of the request element Plus "result".
You can use a series of built-in mapping flags to liberate yourself from standard XML maps. For example, you can use the [XmlType] flag to customize the name and namespace of a type. You can use the [XmlElement] and [XmlAttribute] flags to control how parameters or class members are mapped to elements or attributes, respectively. You can use the [SoapDocumentMethod] flag to control how the method itself maps to the element name in the request/Response message. For example, you can look at a variety of flags for the following version of the distance example:
Using system;using system.web.services;using system.web.services.protocols;using system.xml.serialization;public Class Point { [XmlAttribute] is public double x; [XmlAttribute] public double Y;} [WebService (namespace= "Urn:geometry")]public class Geometry { [WebMethod] [SoapDocumentMethod ( Requestelementname= "Calcdistance", responseelementname= "Calculateddistance")] [Return:xmlelement (" Result ')] public double Distance ( [XmlElement ("O")]point orig, [XmlElement ("D")]point dest) { return Math.sqrt (Math.pow (Orig.x-dest.x, 2) + Math.pow (ORIG.Y-DEST.Y, 2)); }
This version of distance requires that the SOAP message format entered is as follows:
<soap:envelope xmlns:soap= "http://schemas.xmlsoap.org/soap/envelope/" > <soap:Body> <calcdistance xmlns= "Urn:geometry" > <o x= "0" y= "0"/> <d x= "3" y= "4"/> </ Calcdistance> </soap:Body></soap:Envelope>
The SOAP response message that it generates is formatted as follows:
<soap:envelope xmlns:soap= "http://schemas.xmlsoap.org/soap/envelope/" > <soap:Body> <calculateddistance xmlns= "Urn:geometry" > <result>5</result> </ Calculateddistance> </soap:Body></soap:Envelope>
The. asmx handler uses the SOAP document/literal style to implement and describe the default mappings shown above. This means that the WSDL definition will contain literal XML Schema definitions that describe the request and response elements used in the SOAP message (for example, no SOAP encoding rules are used).
The. asmx handler can also use the SOAP rpc/encoded style. This means that the SOAP body contains an XML representation of an RPC invocation, and that the parameters are serialized using the SOAP encoding rule (for example, XML Schemas are not required). To achieve this goal, use [SoapRpcService] and [SoapRpcMethod] instead of [SoapDocumentService] and [SoapDocumentMethod] flags. If you want to understand the differences between these styles, see Understanding SOAP.
From the information above you can see that it is possible to completely customize how to map a given method to a SOAP message. XmlSerializer provides a powerful serialization engine and many of the features we don't discuss in this article. For more information on how XmlSerializer works, consult moving to. NET and Web Services.
as a complement to the parallelism of processing parameters, the. asmx handler can also parallel/serialize the SOAP header. SOAP headers are handled differently than parameters because they are typically considered to be outside the scope of information and are not directly associated with a particular method. For this reason, the typical head handling is done by the listening layer, so that the WebMethod does not have to do head processing at all.
However, if you want to handle header information in WebMethod, you must provide a. NET class that demonstrates the SoapHeader (which describes the XML schema type of the head). Then you define a member variable of that type as the position marker for the header instance. Finally, you annotate each WebMethod that needs access to the header, specifying the name of the field you want to work with.
For example, take a look at the following SOAP request containing the UsernameToken header for authentication purposes:
<soap:envelope xmlns:soap= "http://schemas.xmlsoap.org/soap/envelope/" > <soap:Header> <x:usernametoken xmlns:x= "http://example.org/security" > <username>Mary</username> <password>yraM</password> </x:UsernameToken> </soap:Header> <soap:body > <calcdistance xmlns= "Urn:geometry" > ...
In order for the. asmx handler to be able to parallel the header, you first have to define a. NET class that describes the implied XML Schema type (Note: If you already have the XML schema for that header, you can use XSD.EXE/C to generate this class). In this case, the corresponding class is as follows:
[XmlType (namespace= "http://example.org/security")] [XmlRoot (namespace= "http://example.org/security")]public class Usernametoken:soapheader {public string Username; public string Password;}
Next, you must simply define a member variable in the WebMethod class to hold an instance of the header class and use the [SoapHeader] flag to annotate the WebMethod as follows:
Using system;using system.web.services;using System.Web.Services.Protocols; [WebService (namespace= "Urn:geometry")]public class Geometry {public UsernameToken Token; [WebMethod] [SoapHeader ("Token")] Public double Distance (point orig, point dest) { if (! Token.username.Equals (Reverse (Token.password)) throw new Exception ("Access Denied"); Return Math.sqrt (Math.pow (Orig.x-dest.x, 2) +math.pow (ORIG.Y-DEST.Y, 2)); }
Then, in WebMethod you can access the token field provided by the header and extract the information. You can also use the same technique to send the head back to the client-you simply specify the direction of the head in the [SoapHeader] flag declaration. For more information about handling SOAP headers in the WebMethod framework component, consult the digging into soap Headers with the. NET Framework.
. An ASMX handler is also provided. The automatic serialization of the net exception. Any unhandled exception captured by. asmx is automatically serialized into the SOAP fault element in the response. For example, in the previous example, if the username does not match the password, the code throws one. NET exception. The ASMX handler then captures this exception Shing into the SOAP response shown below:
<soap:envelope xmlns:soap= "http://schemas.xmlsoap.org/soap/envelope/" > <soap:Body> &L T;soap:fault> <faultcode>soap:Server</faultcode> <faultstring>server is unable to proc ESS request. --> access denied</faultstring> <detail/> </soap:Fault> </soap:body></soap:envelop E>
If you need more SOAP fault element control, you can explicitly throw a SoapException object that specifies all the details of the SOAP fault element, such as FaultCode, faulstring, Faultactor and detail elements. You can see the using SOAP faults for more information. As shown above, the
indicates how WebMethod must understand the underlying serialization engine and its various options. The advantage of the serialization engine is that it hides all the underlying XML API code that is typically required to write a custom handler. However, while most developers find this to be positive, some developers think it is a flaw because they still want to manually wrap SOAP messages in the WebMethod implementation. For more information about how to implement this hybrid approach, see Accessing Raw SOAP Messages in asp.net Web Services.
Automatically generate WSDL
Once you have written and configured a WebMethod, the client needs to know what the correct SOAP message looks like in order to successfully communicate with it. The standard way to provide a Web Service description is WSDL (or embedded XSD definitions). To help adapt to this situation, the. asmx handler automatically generates a document page that humans can read and a WSDL definition that accurately reflects the WebMethod interface. If you apply a series of mapping flags to webmethods, they will be reflected in the resulting document.
If you browse to the. asmx file, you will see a document page that looks like the one you can read in Figure 2. The document page is generated by an. aspx page called DefaultWsdlHelpGenerator.aspx, located in C:\windows\Microsoft.NET\Framework\ v1.0.3705\config. If you open this file, you can see that this is just one use. NET reflection generates a standard ASP.net page for a document. This feature keeps your document in sync with your code. You can simply modify this file to customize the generated document.
You can bypass document generation based on virtual directories by specifying a different document file in the Web.config file:
<configuration> <system.web> <webServices> <wsdlhelpgenerator href= " Mydocumentation.aspx "/> </webServices> ...
If the client raises a GET request for the. ASMX endpoint that has "? wsdl" in the request string, the. asmx handler generates a WSDL definition to replace the document that can be read. This WSDL definition can be used by clients to generate proxy classes that automatically understand how to communicate with Web services (for example, using Wsdl.exe in. net).
To customize the WSDL generation process, you can write a SoapExtensionReflector class and register with the WebMethods framework component in the Web.config file. Then, when the. asmx handler generates a WSDL definition, it invokes your reflection class, giving you the opportunity to customize the definition that is ultimately provided to the client. If you want to learn more about how to write SoapExtensionReflector classes, check out the soapextensionreflectors in asp.net Web Services.
You can use two different techniques to bypass the WSDL generation process. The first is that you can provide a static WSDL document for the client access in the virtual directory and delete the document Generation section in the Web.config file, as follows:
<configuration> <system.web> <webServices> <protocols> <remove Name= "Documentation"/> </protocols> ...
Another technique that is slightly more automated is to use the [webservicesbinding] flag to specify the location of the static WSDL document in the virtual directory where the WebMethod class is implemented. You must also use the [SoapDocumentMethod] flag to specify the name of the WSDL that is to be used for each WebMethod implementation. With these, the automated WSDL generation process will import your static WSDL file and wrap a new service description around it. If you want to learn more about this technology, consult the place XML messaging design ahead of Schema planning to improve WEB Service interoperability.
Currently, WSDL is extremely difficult to write manually because there are not many WSDL editors available. Therefore, automated document/WSDL generation is a valuable part of the WebMethods framework component, and many developers will rely on it for a long time.
Conclusion
Asp. NET WebMethods Framework component provides an efficient way to build Web services. WebMethods makes it possible to expose traditional. NET methods to Web service operations in support of HTTP, XML, XML Schema, SOAP, and WSDL. The webmethods (. asmx) handler automatically assigns the input SOAP message to the appropriate method by automatically serializing the input XML element into the corresponding. NET object. To simplify integration with clients, the. asmx handler also provides automatic support for generating human-readable (HTML) and computer-readable (WSDL) documents.
Although the WebMethods framework component is somewhat restrictive compared to the custom ihttphandlers, it also provides a powerful extensibility model, the SOAP extension framework component that we know. SOAP extensions allow you to introduce additional functionality as needed. For example, Microsoft is. NET publishes Web Services Enhancements 1.0 (WSE), which simply provides a soapextension class that introduces support for several GXA specifications for the WebMethods framework component. If you need to know more about writing SOAP extensions, see Fun with soap Extensions.