Developing a Web Service


Thus far, you've looked at the standard web service files created by the Visual Studio web service template. Now you're ready to explore developing an actual web service with Visual Studio 2005. For this example, you will develop a CustomerProfile web service. This web service will provide methods for retrieving customer information from a data store and saving changes to that information. Along the way, you will look at the finer points of developing a .NET web service.

Creating the Web Service

To create the web service, you add a new web service item to an ASP .NET application. For this example, you start with a web service project and create the CustomerProfile.asmx service. Next, you remove the HelloWorld sample method and in its place develop your web methods. These sample methods include GetCustomerProfile and SaveCustomer.

The GetCustomerProfile method takes a customer ID as a parameter and returns a customer object. The SaveCustomer method takes an instance of this same customer object but does not return a value. Listing 16.1 shows the sample code for the service.

Listing 16.1. Customer Profile Web Service

using System; using System.Web; using System.Web.Services; using System.Web.Services.Protocols; using System.Data; [WebService(Namespace = "http://www.brilliantstorm.com/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] public class CustomerProfile: WebService {     public CustomerProfile() {     }     [WebMethod(Description = "Used to return a customer's profile.")]     public BusinessEntities.Customer GetCustomerProfile(int customerId) {         EntityServices.CustomerProfile custProfile =           new EntityServices.CustomerProfile();         return custProfile.GetCustomer(customerId);     }     [WebMethod(Description = "Saves a customer")]     public void SaveCustomer(BusinessEntities.Customer customer) {         EntityServices.CustomerProfile custProfile =           new EntityServices.CustomerProfile();         custProfile.SaveCustomer(customer);     } }

It is important to note that Listing 16.1 references a couple of projects that are outside the web service project. The first is the BusinessEntities project. This project (and namespace) contains the actual definition for the Customer object. You reference this project the same way you add a reference to any other project.

The second project referenced is EntityServices. This namespace provides the actual implementation of the code that executes on behalf of the service. In fact, the SaveCustomer web method is actually a proxy for the EntityServices.CustomerProfile.SaveCustomer method. This latter method does the work to actually save the customer.

This proxy implementation pattern is optional. You could define all your execution logic right inside the web service. However, we are showing this example for two reasons. The first is that most applications built today leverage some existing code. It can be useful to build a proxy to expose this existing code through web services. The second point is that this is just good design. Having the implementation code inside a separate object can lead to reuse, can enable easier unit testing, and can enable client scenarios that are more traditional (and do not rely on web services).

Tip

When you're building a web service, it is best to group functionality into course-grained interfaces. You don't want web methods that do a number of fine-grained operations such as setting properties prior to calling a method. This chatty nature can be expensive when communicating across the Internet.

Of course, this approach is also contrary to most object-oriented application designs. Therefore, the use of a proxy object to bundle operations around a business object is ideal. The business object can be serialized and passed across the wire. On the other side, it can be deserialized and then worked with in an in-process manner (where chatty calls are not expensive).


Now that you have built the sample service, you're ready to look at what makes this class a web service. In addition, the following sections elaborate on the definition of web methods.

The WebService Attribute Class

The WebService attribute class (also called WebServiceAttribute) can be used to provide additional details about a given web service. You may apply this attribute when declaring a class as a web service. However, the attribute is not required. It merely gives context about a web service. For example, we used the WebService attribute on the CustomerProfile class declaration to provide details about the web service's namespace.

The following are the descriptive elements you can define with the WebService attribute class:

  • DescriptionUsed to define a description of the web service. This description will be provided to consumers of your web service and in related documentation. You should always supply this web service description.

  • NamespaceUsed to declare the namespace for your web service (tempuri.org by default). This is similar to namespaces as you know them inside .NET. However, these namespaces are meant to be unique across the web on which they operate. Therefore, you should always define a namespace using a URL that you own and control. This can be a company Internet address, for example.

  • NameUsed to define a different name for your web service. The name of your web service need not be restricted to the naming confines of .NET. Therefore, you can use this parameter to create a new name for your web service.

The WebService Class

The WebService class represents the base class for .NET web services. This is not to be confused with the WebService attribute class (see the preceding section). You derive from this class in order to use the common ASP.NET objects (Session, Application, Context, and so on). However, it is not mandatory that you do so. Visual Studio enforces this inheritance when you define a new web service, but you can remove this code if you have no intention of leveraging the ASP objects within your web service. If you choose to derive from WebService, then you access these ASP.NET objects the same way you would inside any web application.

The WebMethod Attribute Class

The WebMethod attribute class is used to indicate that a method in your service should be exposed via the web service. This declaration is mandatory for all methods that you intend to make available through the web service.

There are a number of parameters you can set when defining a web method. These parameters control how the web method operates. For the example, you will simply set the Description parameter to document a description of the method. However, the following provides a more comprehensive list of parameters on the WebMethod attribute:

  • DescriptionUsed to provide a description of the web method. This description will appear to calling clients and on help documentation related to the web method.

  • EnableSessionUsed to indicate whether session states should be enabled for the given web method. Setting this value to TRue allows you to store and retrieve items in the session. If you set this parameter to true and inherit from WebService, you access the session from the Session object (WebService.Session). If you are not inheriting from WebService, you can still set this parameter to TRue. However, to get to the session object, you will have to traverse the HttpContext.Current.Session path.

  • CacheDurationUsed to indicate that the results of the web service should be cached for a specific duration. You set the duration (in seconds) for this parameter. Enabling this cache will result in the caching of the response for every unique set of parameters passed to the web service (similar to ASP.NET output caching).

  • MessageNameUsed to define an alias or separate name for a given web method. This capability is useful if you intend to have overloaded methods that .NET supports but web services do not. In this way, you can keep your overloaded methods and then apply a unique name to each one using this parameter.

  • BufferResponseUsed to indicate whether the entire response should be buffered in the server's memory before passing it back across the wire to the calling client. The default setting for this parameter is true. If you set it to False, the response will be buffered in chunks of 16KB, with each chunk being sent to the client one at a time.

  • transactionOptionUsed to indicate whether the web service should be the root of a transaction. By default, web services cannot be enlisted in other transactions. They can, however, invoke objects that participate in a transaction along with the single web service.

Accessing and Invoking the Web Service

Visual Studio and the .NET Framework enable you to view a given web service inside the web browser. This capability can be useful for both testing a web service and discovering how one works (the messages they require and return). To access a web service, you first build (compile) it in Visual Studio and then access the .asmx file in a browser.

Figure 16.4 shows the CustomerProfile web service example in a browser window. Notice that both methods of the service are listed. Each method's description is also provided. This is the same description entered in the web method definition (WebMethodAttribute).

Figure 16.4. Navigating to the web service.


Viewing the Formal Web Service Description

To see the actual formal description of the web service as it is defined in WSDL, you can select the link Service Description from the page shown in Figure 16.4. When you click this link, the WSDL parameter is passed to the .asmx file on the QueryString. This tells .NET to return the WSDL of the service.

This WSDL is generated for you by .NET. It conforms to the WSDL standards and can therefore be used by clients that want to access your service. These clients use this WSDL to understand how your web service operates.

Note

.NET ships with a tool named Disco.exe. Visual Studio uses this tool to generate files related to the understanding and discovery of web services. You, too, can leverage this tool from the command line to generate these documents and store them for examination and use.

The documents created by Disco.exe serve as the input for client applications that consume the web service. These client applications are created using a related tool called WSDL.exe.


You can find the complete listing of the WSDL for the CustomerProfile service in Listing 16.2. This listing is easier to view in a browser (where you get color-coding and a tree-like structure to navigate the XML). However, the listing is provided here for your reference. As you scan it, notice how each service is defined. Also notice how the Customer complex type is embedded inside the WSDL. This complex type was generated based on the sample Customer object (BusinessEntities.Customer). Recall that this type is a return value to one method and a parameter to another. You can see that .NET is converting this to an XML type for use by web services.

Listing 16.2. The Web Service WSDL

[View full width]

<?xml version="1.0" encoding="utf-8"?> <wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tm="http:/ /microsoft.com/wsdl/mime/textMatching/" xmlns:soapenc="http://schemas.xmlsoap.org/soap /encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="http://www .brilliantstorm.com/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http:/ /schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"  targetNamespace="http://www.brilliantstorm.com/" xmlns:wsdl="http://schemas.xmlsoap.org /wsdl/">  <wsdl:types>    <s:schema elementFormDefault="qualified" targetNamespace="http://www.brilliantstorm.com/">      <s:element name="GetCustomerProfile">        <s:complexType>          <s:sequence>            <s:element minOccurs="1" maxOccurs="1" name="customerId" type="s:int" />          </s:sequence>        </s:complexType>      </s:element>      <s:element name="GetCustomerProfileResponse">        <s:complexType>          <s:sequence>            <s:element minOccurs="0" maxOccurs="1" name="GetCustomerProfileResult"  type="tns:Customer" />          </s:sequence>        </s:complexType>      </s:element>      <s:complexType name="Customer">        <s:sequence>          <s:element minOccurs="0" maxOccurs="1" name="Email" type="s:string" />          <s:element minOccurs="0" maxOccurs="1" name="Address1" type="s:string" />          <s:element minOccurs="0" maxOccurs="1" name="Address2" type="s:string" />          <s:element minOccurs="0" maxOccurs="1" name="City" type="s:string" />          <s:element minOccurs="0" maxOccurs="1" name="State" type="s:string" />          <s:element minOccurs="0" maxOccurs="1" name="Zip" type="s:string" />          <s:element minOccurs="0" maxOccurs="1" name="Phone" type="s:string" />          <s:element minOccurs="1" maxOccurs="1" name="ContactViaEmail" type="s:boolean" />          <s:element minOccurs="1" maxOccurs="1" name="ContactViaPhone" type="s:boolean" />          <s:element minOccurs="0" maxOccurs="1" name="Name" type="s:string" />          <s:element minOccurs="0" maxOccurs="1" name="Description" type="s:string" />          <s:element minOccurs="1" maxOccurs="1" name="Id" type="s:int" />        </s:sequence>       </s:complexType>       <s:element name="SaveCustomer">        <s:complexType>          <s:sequence>            <s:element minOccurs="0" maxOccurs="1" name="customer" type="tns:Customer" />          </s:sequence>        </s:complexType>      </s:element>      <s:element name="SaveCustomerResponse">        <s:complexType />      </s:element>    </s:schema>  </wsdl:types>  <wsdl:message name="GetCustomerProfileSoapIn">    <wsdl:part name="parameters" element="tns:GetCustomerProfile" />  </wsdl:message>  <wsdl:message name="GetCustomerProfileSoapOut">    <wsdl:part name="parameters" element="tns:GetCustomerProfileResponse" />  </wsdl:message>  <wsdl:message name="SaveCustomerSoapIn">    <wsdl:part name="parameters" element="tns:SaveCustomer" />  </wsdl:message>  <wsdl:message name="SaveCustomerSoapOut">    <wsdl:part name="parameters" element="tns:SaveCustomerResponse" />  </wsdl:message>  <wsdl:portType name="CustomerProfileSoap">    <wsdl:operation name="GetCustomerProfile">      <wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> Used to return a  customer's profile.</wsdl:documentation>      <wsdl:input message="tns:GetCustomerProfileSoapIn" />      <wsdl:output message="tns:GetCustomerProfileSoapOut" />    </wsdl:operation>    <wsdl:operation name="SaveCustomer">     <wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> Saves a customer</ wsdl:documentation>     <wsdl:input message="tns:SaveCustomerSoapIn" />     <wsdl:output message="tns:SaveCustomerSoapOut" />   </wsdl:operation> </wsdl:portType> <wsdl:binding name="CustomerProfileSoap" type="tns:CustomerProfileSoap">   <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />   <wsdl:operation name="GetCustomerProfile">     <soap:operation soapAction="http://www.brilliantstorm.com/GetCustomerProfile"  style="document" />     <wsdl:input>       <soap:body use="literal" />     </wsdl:input>     <wsdl:output>       <soap:body use="literal" />     </wsdl:output>   </wsdl:operation>   <wsdl:operation name="SaveCustomer">     <soap:operation soapAction="http://www.brilliantstorm.com/SaveCustomer"  style="document" />     <wsdl:input>       <soap:body use="literal" />     </wsdl:input>     <wsdl:output>       <soap:body use="literal" />     </wsdl:output>   </wsdl:operation> </wsdl:binding> <wsdl:binding name="CustomerProfileSoap12" type="tns:CustomerProfileSoap">   <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />   <wsdl:operation name="GetCustomerProfile">     <soap12:operation soapAction= "http://www.brilliantstorm.com/GetCustomerProfile"  style="document" />     <wsdl:input>       <soap12:body use="literal" />     </wsdl:input>     <wsdl:output>       <soap12:body use="literal" />     </wsdl:output>   </wsdl:operation>   <wsdl:operation name="SaveCustomer">     <soap12:operation soapAction="http://www.brilliantstorm.com/SaveCustomer"  style="document" />     <wsdl:input>       <soap12:body use="literal" />     </wsdl:input>     <wsdl:output>       <soap12:body use="literal" />     </wsdl:output>   </wsdl:operation> </wsdl:binding> <wsdl:service name="CustomerProfile">   <wsdl:port name="CustomerProfileSoap" binding="tns:CustomerProfileSoap">     <soap:address location="http://localhost:1154/UnleashedServiceLayer/GetCustomerProfile .asmx" />   </wsdl:port>   <wsdl:port name="CustomerProfileSoap12" binding="tns:CustomerProfileSoap12">     <soap12:address location="http://localhost:1154/UnleashedServiceLayer /GetCustomerProfile.asmx" />    </wsdl:port>  </wsdl:service> </wsdl:definitions>

Viewing the Web Method

When you click on the web method name, .NET generates a web form for you to use to test the given web service. This form is accessed from the .asmx file (URI) with the QueryString parameter op (operation). You pass the name of the web method to this parameter. For the example, look at the web method named GetCustomerProfile. Figure 16.5 shows this web form.

Figure 16.5. The GetCustomerProfile web method.


The top part of the form allows you to enter parameters for the web method and then invoke the actual web method using the HTTP POST protocol. This protocol is just one way to invoke the web method. Recall that you also use SOAP over HTTP and so on. This page shows actual examples of a SOAP request and response as well as HTTP. These examples can be useful if you want to see how messages should be constructed for these protocols.

As an example, Listing 16.3 shows a SOAP message request for this web method. Notice that it indicates the <customerId> element must be passed to the method. This is of the primitive type int. Listing 16.4 shows the correlated SOAP response from the call. Notice here the SOAP result is contained in the element <GetCustomerProfileResult>. This page also contains examples of SOAP 1.1 and HTTP POST requests and responses.

Listing 16.3. SOAP 1.2 Request

[View full width]

POST /UnleashedServiceLayer/GetCustomerProfile.asmx HTTP/1.1 Host: localhost Content-Type: application/soap+xml; charset=utf-8 Content-Length: length <?xml version="1.0" encoding="utf-8"?> <soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http:// www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">   <soap12:Body>     <GetCustomerProfile xmlns="http://www.brilliantstorm.com/">       <customerId>int</customerId>     </GetCustomerProfile>   </soap12:Body> </soap12:Envelope>

Listing 16.4. SOAP 1.2 Response

[View full width]

HTTP/1.1 200 OK Content-Type: application/soap+xml; charset=utf-8 Content-Length: length <?xml version="1.0" encoding="utf-8"?> <soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http:// www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">   <soap12:Body>     <GetCustomerProfileResponse xmlns="http://www.brilliantstorm.com/">       <GetCustomerProfileResult>         <Email>string</Email>         <Address1>string</Address1>         <Address2>string</Address2>         <City>string</City>         <State>string</State>         <Zip>string</Zip>         <Phone>string</Phone>         <ContactViaEmail>boolean</ContactViaEmail>         <ContactViaPhone>boolean</ContactViaPhone>         <Name>string</Name>         <Description>string</Description>         <Id>int</Id>       </GetCustomerProfileResult>     </GetCustomerProfileResponse>   </soap12:Body> </soap12:Envelope>

Invoking the Web Method

To invoke the web method, you enter a value for the parameters and click the Invoke button (as shown in Figure 16.5). Doing so executes the web service and returns the results. The results are sent back as XML (as defined by the message). Remember, this invocation is HTTP POST. Figure 16.6 shows the results from the example.

Figure 16.6. GetCustomerProfile results.


Note

You can use this method only to invoke web methods that take simple (primitive) data types as parameters. If your web method takes a complex type (SaveCustomer, for example), then you can still see the request/response examples but cannot invoke the web method in this manner.





Microsoft Visual Studio 2005 Unleashed
Microsoft Visual Studio 2005 Unleashed
ISBN: 0672328194
EAN: 2147483647
Year: 2006
Pages: 195

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net