Section 15.8. WebMethod Attribute

15.8. WebMethod Attribute

As explained previously, a web service is defined by a WebService class. It is not necessary for the WebService class to expose all of its methods to consumers of the web service. Each method you do want to expose must do the following:

  • Be declared as public .

  • Have the WebMethod attribute placed before the method declaration. (The WebMethod attribute comes from the WebMethodAttribute class, which is contained in the System.Web.Services namespace.)

As you saw in the previous examples in this chapter, the basic WebMethod attribute looks something like the highlighted code in the following snippet:

  [WebMethod]  public string GetName(string StockSymbol) 

The WebMethod attribute has properties that are used to configure the behavior of the specific web method. Here is the syntax:

 [WebMethod(PropertyName=value)] 

PropertyName is a valid property accepted by the WebMethod attribute (these are described below), and value is the value to be assigned to that property. If there are multiple WebMethod properties, separate each property/value pair with a comma within a single set of parentheses as in this example:

 [WebMethod(BufferResponse=false, Description="Sample description")] 

The following sections describe the WebMethod properties.

15.8.1. The BufferResponse Property

By default, ASP.NET buffers the entire response to a request before sending it from the server to the client. Under most circumstances, this is the optimal behavior. However, if the response is very lengthy, you might want to disable this buffering by setting the WebMethod attribute's BufferResponse property to false . If it is set to false , the response will be returned to the client in 16KB chunks . The default value is true .

Here is the syntax for BufferResponse :

 [WebMethod(BufferResponse=false)] 

15.8.2. CacheDuration Property

Web services, like web pages, can cache the results returned to clients as is described fully in Chapter 17. If a client makes a request identical to a request made recently by another client, the server will return the response stored in the cache. This can result in a huge performance gain, especially if servicing the request is an expensive operation (such as querying a database or performing a lengthy computation).

For the cached results to be used, the new request must be identical to the previous request. If the web method has parameters, the parameter values must be identical. So, for example, if the GetPrice web method of the StockTicker web service is called with a value of msft passed in as the stock symbol, that result will be cached separately from a request with a value of dell passed in. If the web method has multiple parameters, all the parameter values must be the same as the previous request for the cached results from that request to be returned.

The CacheDuration property defines how many seconds after the initial request the cached page is sent in response to subsequent requests . Once this period has expired , a new page is sent. CacheDuration is set to 30 seconds as follows :

 [WebMethod(CacheDuration=30)] 

The default value for CacheDuration is zero, which disables caching of results.

If the web method is returning data that do not change much (say, a query against a database that is updated once hourly), then the cache duration can be set to a suitably long value, say 1800 (30 minutes). You could set the cache duration in this case to 3600 (60 minutes) if the process of updating the database forces the cache to refresh by making a call to the WebMethod after the database is updated.

On the other hand, if the data returned is very dynamic, then you will want to set the cache duration to a short time or to disable it altogether. Also, if the web method does not have a relatively finite range of possible parameters, then caching may not be appropriate.

15.8.3. Description Property

The WebMethod attribute's Description property allows you to attach a descriptive string to a web method. This description will appear on the web service help page when you test the web service in a browser.

Also, the WebMethod description will be made available to the consumer of the web service as you will see in the next chapter. When a representation of the web service is encoded into the SOAP message that is sent out to potential consumers, the WebMethod Description property is included.

The syntax for Description is as follows:

 [WebMethod(Description="Returns the stock price for the input stock symbol.")] 

15.8.4. EnableSession Property

The WebMethod attribute's EnableSession property, if set to true , will enable session state for the web method. The default value is false . (For a general discussion of session state, see Chapter 6.)

If the EnableSession property is set to true and the web service inherits from the WebService class (see earlier sections for a description of inheriting from the WebService class), the session state collection can be accessed with the WebService.Session property. If the web service does not inherit from the WebService class, the session state collection can be accessed directly from HttpContext.Current.Session .

As an example, the code in Example 15-7 adds a per-session hit counter to the ongoing StockTickerComplete web service example.

Example 15-7. HitCounter WebMethod with session state enabled
 [WebMethod(Description="Number of hits per session.", EnableSession=true)] public int HitCounter(  ) {    if (Session["HitCounter"] == null)    {       Session["HitCounter"] = 1;    }    else    {       Session["HitCounter"] = ((int) Session["HitCounter"]) + 1;    }    return ((int) Session["HitCounter"]); } 

Enabling session state adds additional overhead to the application. Leaving session state disabled may improve performance.

In Example 15-7, it would probably be more efficient to use a member variable to maintain the hit counter, rather than session state, since the example as written entails two reads of the session state and one write, while a member variable would entail only one read and one write. However, session state is often useful as a global variable that can exceed the scope of a member variable.

Session state is implemented via HTTP cookies in ASP.NET web services, so if the transport mechanism is something other than HTTP (say, SMTP), then the session state functionality will be unavailable.

15.8.5. MessageName Property

You can have more than one method in your C# class with the same name . They are differentiated by their signature (the quantity, data type, and order of their parameters). Each unique signature can be called independently. This is called method overloading .

Web services forbid overloaded methods. The WebMethod attribute's MessageName property eliminates the ambiguity caused by having more than one method with the same name. It allows you to assign a unique alias to each version of the overloaded method. When the overloaded method is referred to in SOAP messages, the MessageName , and not the method name, will be used.

Consider Example 15-8. Two methods are added to the StockTickerComplete web service, both named GetValue . They differ in that one accepts a single string parameter, and the other takes a string and an integer.

Example 15-8. GetValue WebMethods which generate an error
 // WebMethod generates an error [WebMethod(Description="Returns the value of the users holdings " +                         " in a specified stock symbol.")] public double GetValue(string StockSymbol) {    /* Put code here to get the username of the current user, fetch both       the current price of the specified StockSymbol and number of shares       held by the current user, multiply the two together, and return the       result.    */    return 0; } // WebMethod generates an error [WebMethod(Description="This method returns the value of a " +              "specified number of shares in a specified stock symbol.")] public double GetValue(string StockSymbol, int NumShares) {    /*  Put code here to get the current price of the specified       StockSymbol, multiply it times NumShares, and return the result.    */    return 0; } 

If you attempt to test either of these in a browser, it will return an error similar to that shown in Figure 15-5.

Figure 15-5. Conflicting WebMethod names

If you modify the code in Example 15-8 by adding the MessageName property, highlighted in Example 15-9, then everything should compile nicely . Except you get another error page with a lengthy error message to the effect that your web service does not conform to WS-I Basic Profile v.1.1 since "operation name overloading... is disallowed ."

Example 15-9. GetValue WebMethods with MessageName property
 [WebMethod(Description="Returns the value of the users holdings " +                "in a specified stock symbol.",  MessageName="GetValuePortfolio")]  public double GetValue(string StockSymbol) {    /*  Put code here to get the username of the current user, fetch       both the current price of the specified StockSymbol and number       of shares held by the current user, multiply the two together,       and return the result.    */   return 0; } [WebMethod(Description="Returns the value of a specified " +                   "number of shares in a specified stock symbol.",  MessageName="GetValueStock")]  public double GetValue(string StockSymbol, int NumShares) {    /*  Put code here to get the current price of the specified       StockSymbol, multiply it times NumShares, and return the       result.    */    return 0; } 

Recall that the default WebServiceBinding attribute inserted by VS2005 specifies conformance with WS-I BP v1.1. That specification will disallow method overloading (even using the MessageName property) if the two methods are in the same binding . Your choices are the following:

  • Rename the methods so the method is no longer overloaded.

  • Turn off enforced conformance with WS-I BP v1.1. Do this by setting the value of the ConformsTo property of the WebServiceBinding attribute to WsiProfiles.None .

    This is a bad idea because it will cause interoperability problems. If you own both sides of the wire and don't have to conform to open standards, then you should not be using a web service at all; you should be using remoting, which is much more efficient.

  • Create a new binding to hold the overloaded method.

The first choice is simplest. The third choice may be preferred if no client needs to connect to your web service and have access to more than one form of the overloaded method. To add a new binding, add another WebServiceBinding attribute to the class, adjacent to the original attribute. It will be identical to the original except for the addition of the Name property, highlighted in Example 15-10.

Example 15-10. WebServiceBinding attribute with Name
 [WebServiceBinding(  Name = "OverloadedGetValue",  ConformsTo = WsiProfiles.BasicProfile1_1,    EmitConformanceClaims = true)] 

For a web method to use this binding, rather than the default binding, it must be decorated with the SoapDocumentMethod attribute shown highlighted in Example 15-11. The Binding property of this attribute specifies which non-default binding to use.

Example 15-11. SoapDocumentMethod attribute
  [SoapDocumentMethod(Binding = "OverloadedGetValue")]  [WebMethod(Description = "Returns the value of a specified " +                   "number of shares in a specified stock symbol.",              MessageName = "GetValueStock")] public double GetValue(string StockSymbol, int NumShares) {    /*  Put code here to get the current price of the specified       StockSymbol, multiply it times NumShares, and return the result.    */    return 0; } 

Now consumers of the web service can call GetValuePortfolio or GetValueStock rather than GetValue .

To see the impact of this change, examine the WSDL, which is the description of the web service used by clients of the web service. You can look at the WSDL by clicking the Service Description link in the test page you get when you run the web service. Alternatively, you can enter in a browser directly ( assuming you have created a virtual directory for the web service) the URL for the .asmx , followed by ?WSDL .

If you examine the WSDL for StockTickerComplete so far, then search for the first occurrence of GetValue (as a whole word), you will see something like Figure 15-6.

You can see that the tag for GetValue :

 <wsdl:operation name="GetValue"> 

is defined within a <wsdl:portType> section where the name is OverloadedGetValue . The portType element name corresponds to the additional web service binding added in Example 15-10. This has the <wsdl:input> name of GetValueStock , as you would expect from Example 15-11.

Searching further, you will find the XML listed in the following code snippet:

 <wsdl:portType name="ServiceSoap">        <wsdl:operation name="GetPrice">           <wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">              Returns the stock price for the input stock symbol.           </wsdl:documentation> 

Figure 15-6. MessageName WSDL

 <wsdl:input message="tns:GetPriceSoapIn" />           <wsdl:output message="tns:GetPriceSoapOut" />        </wsdl:operation>     .     .     .        <wsdl:operation name="GetValue">           <wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">             Returns the value of the users holdings in a specified             stock symbol.           </wsdl:documentation>           <wsdl:input name="GetValuePortfolio"                       message="tns:GetValuePortfolioSoapIn" />           <wsdl:output name="GetValuePortfolio"                       message="tns:GetValuePortfolioSoapOut" />        </wsdl:operation>     </wsdl:portType> 

In this snippet, the web method GetValue is associated with the <wsdl:input> name GetValuePortfolio , which corresponds to the MessageName property with that value, all within a portType named ServiceSoap , which is the default binding.

If you run the WebServiceComplete example at the end of this chapter, the default binding will be called StockTickerService because the Name property of the WebService attribute, described shortly, will have been set.


15.8.6. TransactionOption Property

ASP.NET web methods can use transactions (see Chapter 10 for more details on transactions) but only if the transaction originates in that web method. In other words, the web method can only participate as the root object in a transaction. This means that a consuming application cannot call a web method as part of a transaction and have that web method participate in the transaction.

The WebMethod attribute's TRansactionOption property specifies whether or not a web method should start a transaction. There are five legal values of the property, all contained in the transactionOption enumeration. However, because a web method transaction must be the root object, there are only two different behaviors: A new transaction is started or it is not.

These values in the transactionOption enumeration are used throughout the .NET Framework. However, in the case of web services, the first three values produce the same behavior, and the last two values produce the other behavior.

The three values of transactionOption that do not start a new transaction are the following:

  • Disabled (the default)

  • NotSupported

  • Supported

The two values that do start a new transaction are the following:

  • Required

  • RequiresNew

To use transactions in a web service, you must take three additional steps:

  1. Add a reference to System.EnterpriseServices.dll .

    In VS2005, this is done through the Solution Explorer or the Website Add Reference... menu item. To use the Solution Explorer, right-click the web site folder and select Add References.... In either case, you get the dialog box shown in Figure 15-7. Click on the desired component in the list and then click OK.

    This will have the effect of adding an <assemblies> section to web.config , which adds the System.EnterpriseServices assembly.

    When you're coding outside of VS2005, you must add an Assembly directive pointing to System.EnterpriseServices :

     <%@ assembly name="System.EnterpriseServices" %> 


  2. Add the System.EnterpriseServices namespace to the web service. This is done with the following code:

     using System.EnterpriseServices; 

  3. Add a transactionOption property with a value of RequiresNew to the WebMethod attribute. (The value of Required will have the same effect.)

Figure 15-7. Adding a reference to a web service in Visual Studio 2005

Example 15-12 lists another web method added to StockTickerComplete , which has the transactionOption property highlighted set to start a new transaction.

Example 15-12. TransactionOption property of WebMethod attribute
 [WebMethod(Description = "Sets the value of the users holdings " +            "in a specified stock symbol.",  TransactionOption=TransactionOption.RequiresNew)]  public double SetValue(string StockSymbol) {    /*  Put code here to set the value of the specified       StockSymbol.       This method is starts a transaction.    */    return 0; } 

If there are no exceptions thrown by the web method, then the transaction will automatically commit unless the SetAbort method is explicitly called. If an unhandled exception is thrown, the transaction will automatically abort.



Programming ASP. NET
Programming ASP.NET 3.5
ISBN: 0596529562
EAN: 2147483647
Year: 2003
Pages: 173

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