Creating a Web Service

At its simplest, creating a web service in .NET can be almost trivially easy. I’m going to start with a simple inventory query service. Example 10-2 shows the basic ASP.NET skeleton for such a service.

Example 10-2. InventoryQuery.asmx source code
<%@ WebService Language="C#" Class="InventoryQuery" %>

using System.Web.Services;

[WebService(Namespace="http://angushardware.com/InventoryQuery")]
public class InventoryQuery : WebService {
  [WebMethod]
  public int GetNumberInStock(string productCode) {
    return 0;
  }
}

Let’s break this skeleton down into its basic components.

The presence of the @ WebService directive in a file with the .asmx extension tells the ASP.NET provider that the web service is located at InventoryQuery.asmx, that the web service’s source code is written in C#, and that the implementation is in the class named InventoryQuery. The code could also be written in JScript .NET (JS) or Visual Basic .NET (VB). Additionally, the code could actually reside in a separate file, compiled into an assembly located in the .Bin directory relative to the .asmx file:

<%@ WebService Language="C#" Class="InventoryQuery" %>

Warning

There is no restriction on the name of the assembly containing the class that implements a web service, and multiple web services may exist in the same directory. However, if multiple assemblies in the .Bin directory each contain a class with the name listed in an .asmx file, there is no guarantee which one will be used when that web service is invoked.

The WebService attribute comes from the System.Web.Services namespace, and indicates that the class in question represents the implementation of a web service. The Namespace property sets the default namespace for the web service. The WebService attribute also has Name and Description properties, which allow you to set the public name of the web service, and give it a short textual description. The Name property defaults to the name of the class. A class that implements a web service does not actually need to have the WebService attribute; any class can implement a web service:

using System.Web.Services;

[WebService(Namespace="http://angushardware.com/")]

Warning

Although the Namespace property is optional, if you leave it off the ASP .NET provider will use http://tempuri.org/ as the default, and it will generate many strong hints that you should change the namespace.

Web service implementations can extend the WebService type. The WebService type provides access to state information through its Application, Context, Server, Session, and User properties. Although extending WebService is not required for a web service implementation, I have chosen to do so in this example:

public class InventoryQuery : WebService {

Tip

Although the names are the same, the WebService attribute and the WebService type are completely different beasts. If it helps you to keep the distinction clear, remember that while attribute names always end with Attribute, they also have an alias to the name without Attribute on the end. So the WebService attribute type is actually formally called WebServiceAttribute, whereas the WebService type is just called WebService.

Finally, the GetNumberInStock method represents the InventoryQuery web service’s GetNumberInStock message itself. Right now it will always return 0, since I’ve only created a stub method.

The WebMethod attribute indicates that the method it is attached to implements a particular web service message. By default, the name of the message is the name of the method itself, although the WebMethod attribute has a MessageName property that allows you to override the name. WebMethod also has an optional Description property:

[WebMethod]
public int GetNumberInStock(string productCode) {
  return 0;
}

Tip

The WebMethod attribute is the only attribute that is absolutely required to implement a web service using ASP.NET. If no method within a class has the WebMethod attribute, the ASP.NET provider has no way of knowing what messages the web service supports.

To see the InventoryQuery web service in action, make sure the InventoryQuery.asmx file is in C:dotNetAndXml (or whatever directory you set as the application directory in your web server), and navigate your web browser to http://localhost/dotNetAndXml/InventoryQuery.asmx. You should see the page in Figure 10-3.

Main screen of the InventoryQuery web service
Figure 10-3. Main screen of the InventoryQuery web service

This HTML page is generated by the ASP.NET provider, based on the metadata included in the .asmx file and the class that implements the web service. If either the WebService attribute or the WebMethod attribute included a Description property, the descriptive text would be displayed here as well. If any more methods were exposed by attaching the WebMethod attribute to them, they would all be listed on this page as well.

Clicking on the “Service Description” link opens a new window containing the WSDL file that the ASP.NET provider has automatically generated. Example 10-3 shows the generated WSDL for the InventoryQuery web service. Note the similarities to Example 10-1.

Example 10-3. Generated WSDL for the InventoryQuery web service
<?xml version="1.0" encoding="utf-8"?>
<definitions xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" 
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
xmlns:s="http://www.w3.org/2001/XMLSchema" 
  xmlns:s0="http://angushardware.com"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" 
  xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
targetNamespace="http://angushardware.com" 
  xmlns="http://schemas.xmlsoap.org/wsdl/">
  <types>
    <s:schema elementFormDefault="qualified" targetNamespace="http://angushardware.com">
      <s:element name="GetNumberInStock">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="productCode" type="s:string" />
          </s:sequence>
        </s:complexType>
      </s:element>
      <s:element name="GetNumberInStockResponse">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="1" maxOccurs="1" name="GetNumberInStockResult" 
             type="s:int" />
          </s:sequence>
        </s:complexType>
      </s:element>
      <s:element name="int" type="s:int" />
    </s:schema>
  </types>
  <message name="GetNumberInStockSoapIn">
    <part name="parameters" element="s0:GetNumberInStock" />
  </message>
  <message name="GetNumberInStockSoapOut">
    <part name="parameters" element="s0:GetNumberInStockResponse" />
  </message>
  <message name="GetNumberInStockHttpGetIn">
    <part name="productCode" type="s:string" />
  </message>
  <message name="GetNumberInStockHttpGetOut">
    <part name="Body" element="s0:int" />
  </message>
  <message name="GetNumberInStockHttpPostIn">
    <part name="productCode" type="s:string" />
  </message>
  <message name="GetNumberInStockHttpPostOut">
    <part name="Body" element="s0:int" />
  </message>
  <portType name="InventoryQuerySoap">
    <operation name="GetNumberInStock">
      <input message="s0:GetNumberInStockSoapIn" />
      <output message="s0:GetNumberInStockSoapOut" />
    </operation>
  </portType>
  <portType name="InventoryQueryHttpGet">
    <operation name="GetNumberInStock">
      <input message="s0:GetNumberInStockHttpGetIn" />
      <output message="s0:GetNumberInStockHttpGetOut" />
    </operation>
  </portType>
  <portType name="InventoryQueryHttpPost">
    <operation name="GetNumberInStock">
      <input message="s0:GetNumberInStockHttpPostIn" />
      <output message="s0:GetNumberInStockHttpPostOut" />
    </operation>
  </portType>
  <binding name="InventoryQuerySoap" type="s0:InventoryQuerySoap">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
    <operation name="GetNumberInStock">
      <soap:operation soapAction="http://angushardware.com/GetNumberInStock" style="document" />
      <input>
        <soap:body use="literal" />
      </input>
      <output>
        <soap:body use="literal" />
      </output>
    </operation>
  </binding>
  <binding name="InventoryQueryHttpGet" type="s0:InventoryQueryHttpGet">
    <http:binding verb="GET" />
    <operation name="GetNumberInStock">
      <http:operation location="/GetNumberInStock" />
      <input>
        <http:urlEncoded />
      </input>
      <output>
        <mime:mimeXml part="Body" />
      </output>
    </operation>
  </binding>
  <binding name="InventoryQueryHttpPost" type="s0:InventoryQueryHttpPost">
    <http:binding verb="POST" />
    <operation name="GetNumberInStock">
      <http:operation location="/GetNumberInStock" />
      <input>
        <mime:content type="application/x-www-form-urlencoded" />
      </input>
      <output>
        <mime:mimeXml part="Body" />
      </output>
    </operation>
  </binding>
  <service name="InventoryQuery">
    <port name="InventoryQuerySoap" binding="s0:InventoryQuerySoap">
      <soap:address location="http://127.0.0.1/dotNetAndXml/InventoryQuery.asmx" />
    </port>
    <port name="InventoryQueryHttpGet" binding="s0:InventoryQueryHttpGet">
      <http:address location="http://127.0.0.1/dotNetAndXml/InventoryQuery.asmx" />
    </port>
    <port name="InventoryQueryHttpPost" binding="s0:InventoryQueryHttpPost">
      <http:address location="http://127.0.0.1/dotNetAndXml/InventoryQuery.asmx" />
    </port>
  </service>
</definitions>

As you’ll recall from the earlier discussion, the WSDL document provides a complete description of the web service, including all the supported messages, types, port types, bindings, and services. In this case, the ASP.NET provider automatically supports REST-style HTTP POST and GET methods as well as SOAP over HTTP POST.

Tip

There is an alternative style for web services known as Representational State Transfer, or REST. The basic premise of REST is that the HTTP methods GET, POST, PUT, and DELETE provide all the functionality needed to interact with any resources addressable by its URI. WSDL supports REST-based web services as well as SOAP and XML-RPC.

The generated WSDL file in Example 10-3 contains more information than the one in Example 10-1. However, you can see that the only real difference is the inclusion of additional transports for HTTP GET and HTTP POST. The .NET Web Services provider creates these bindings, in addition to SOAP, automatically.

Clicking on the “GetNumberInStock” link in Figure 10-3 will bring you to the page shown in Figure 10-4. This HTML page is also generated automatically by the ASP.NET Web Services provider.

GetNumberInStock test page
Figure 10-4. GetNumberInStock test page

From this page, you can issue a request to the GetNumberInStock method of the InventoryQuery web service. Entering in a value—say, “803B”—and clicking the Invoke button causes the method to be invoked with the given parameter.

This example uses the HTTP GET version of the web service, so the request that was actually sent to the web service provider used the following URL: http://127.0.0.1/dotNetAndXml/InventoryQuery.asmx/GetNumberInStock?productCode=803B.

Because right now the C# code always returns 0, the following response is always returned:

<?xml version="1.0" encoding="utf-8" ?> 
<int xmlns="http://angushardware.com">0</int>

This would also be returned from the HTTP POST version. The SOAP request, however, would look quite a bit different. It would be sent with the following HTTP header and SOAP request envelope:

POST /dotNetAndXml/InventoryQuery.asmx HTTP/1.1
Host: 127.0.0.1
Content-Type: text/xml; charset=utf-8
Content-Length: 365
SOAPAction: "http://angushardware.com/GetNumberInStock"

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <GetNumberInStock xmlns="http://angushardware.com">
      <productCode>803B</productCode>
    </GetNumberInStock>
  </soap:Body>
</soap:Envelope>

The HTTP response header and SOAP response envelope would be the following:

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: 400

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="
http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <GetNumberInStockResponse xmlns="http://angushardware.com">
      <GetNumberInStockResult>0</GetNumberInStockResult>
    </GetNumberInStockResponse>
  </soap:Body>
</soap:Envelope>

If you scroll a little further down the page in Figure 10-4, you’ll see examples of requests and responses in all three versions of the web service.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.149.26.176