Sponsored Links


Resources

.NET Research Library
Get .NET related white papers, case studies and webcasts

Top 5 Web Service MistakesTop 5 Web Service MistakesTop 5 Web Service Mistakes Discuss DiscussDiscuss Printer friendly Printer friendlyPrinter friendly
Top 5 Web Service Mistakes

May 27, 2005

In this article we’re going to discuss five common mistakes that enterprises make when developing web services. It’s important to note that these aren’t logic or syntax mistakes. There are no compiler errors to tell you that something is wrong and no exceptions will be thrown, at least not right away. The issues are architectural not technological. The key then is to avoid them from the beginning because dealing with them after your service is deployed will be much more difficult.

1. Using .NET Specific Types

The fundamental concept behind Web Services is the creation of application logic that is accessible anytime, anywhere, by any other application regardless of technology. Sadly, this also means non .NET applications. The most important aspect of actually achieving interoperability with web services is not contained in code, or at least not directly. For a web service to be interoperable with any technology the data contract it defines must be based on types that are defined by XML Schema, not the .NET Framework. So then, if you use .NET specific types as parameters or return values for a web service, the XML it produces may not be interoperable with Java or some other technology.

Perhaps you’ve seen the demos of how easy it is to create a simple web service that queries a database and returns the data in the form of an ADO.NET Dataset. A Dataset is a completely disconnected version of relational data including tables, keys, and relationships and so it would seem to be the perfect object for passing data across physical boundaries. In the case of web services however, looks are deceiving.

Passing a Dataset as a result or parameter in a web service poses a couple of different problems. The first problem occurs in the WSDL. WSDL (Web Service Description Language) is the XML schema that defines how clients can interact with your service and what parameters and return values it uses. WSDL is often used to generate client-side proxy classes so the more descriptive it is the easier it will be to interact with our service.

Let’s look at an example of a simple service with a method that returns a Dataset containing one row of the Northwind Customers table. Figure 1 shows the WSDL for that service. In particular take note of the highlighted GetCustomerResponse element.


Figure 1

Because the structure of the Dataset isn’t known until runtime, there is no way for the WSDL to describe its internal structure. To accommodate this, the return value (GetCustomerResponse element) for the GetCustomer method has two elements, an element of any type (<s:any>) which is in effect a type of Object and an XML Schema (<s:schema>) which at runtime will describe the structure of the Dataset being returned. This is the web service equivalent of late binding.

Since the client developer has no idea what the structure of the object that your method will return, they won’t be able to generate a very useful proxy. They can still use your web service but now they’ll have to parse the XML returned to find the data they are looking for. Type safety is thrown out the window and you’ve made any non .Net client developer’s job more difficult.

So now you should be saying to yourself “If the WSDL doesn’t define a return type of Dataset, how do all of those demos work?” The answer is in the XML returned at runtime. Figure 2 shows the results of calling our GetCustomer method.


Figure 2

Notice that the NewDataSet element has an additional Microsoft specific attribute called “IsDataset”. This is Visual Studio’s hint that the result should be deserialized to a Dataset. Of course this means nothing if you’re calling this web service from a non .Net client like J2EE.

The second problem inherent with passing Datasets to and from a web service is the sheer amount of data being sent. The XML in Figure 2 only describes the structure of a dataset with one table. As you add tables, relationships, and keys the schema becomes much more complex and much larger. In fact it can quickly become much larger than the actual data being returned. Remember, the more data you send to and from a service the slower that request will be.

The Dataset is probably the most common form of using .NET specific types in Web Services but it isn’t the only one. It makes a lot of sense for a .Net developer to want to use the advanced features and classes provided by the .Net framework. However, if real interoperability is your goal, you will have to fend off these urges. For maximum interoperability, the key is to make sure that all the types used as parameters and return values can be described using the standard XML Schema base types. You can find the definition of all of the XML Schema built-in types at http://www.w3.org/TR/xmlschema-2/.

2. Not Taking Advantage of ASP.NET

The biggest drawback to consuming Web Services is performance. Any improvements that can be made to increase performance are worth the effort. Web services developed in .NET are deployed in ASP.NET and so they have access to all of the same great features of any ASP.Net web application. For performance the two most important features are Caching and SessionState.

Web services can use two types of caching. The first and easiest type is output caching. Output caching allows the result of a service method request to be stored in the server’s cache. Subsequent requests for that method using the same parameters will get the values cached on the server without actually calling the service method and therefore without the overhead of data queries, logic, etc. When the parameters to the method change a new entry is added to the server cache with the specified expiration. To use this feature, just add the “CacheDuration” property to the WebMethodAttribute class. Here is a simple example that caches the result of the method for 120 seconds.

<WebMethod(CacheDuration:=120)> _
    Public Function GetQuote() As Quote

You can also use application data caching to store specific data between requests. Data that is used often but doesn’t change as frequently is a prime candidate to be put into the application’s cache.

To illustrate this lets build a fictional service to retrieve stock quotes. One function that this service offers is the ability to lookup a company’s stock symbol using the company name. A function like this might be called often while the data changes very rarely. In this case we could query the database once at startup and return an array containing all of the company names and corresponding stock symbols and then store that array in the cache with a daily expiration. When a consumer searches for a company’s stock symbol, rather than make a roundtrip to the database for each request we could look it up in the array stored in cache. Figure 3 shows the code required to implement this type of caching.


Figure 3

Web services can also use the built-in SessionState persistence offered via ASP.NET including out-of-process State Server and SQL Server. To enable this feature add “EnableSession=True” to the WebMethod attribute. This is very useful for storing client specific information between method requests. For example, continuing the development of our stock analysis service let’s say our web service allows the consumer to create a custom list of stocks that they are watching. When the client requests the stored list of stocks for that user the first time, we store the list in SessionState before returning it to the consumer. Now we can modify our method to retrieve the list of stocks from SessionState if the consumer didn’t send a new list. This can speed up the performance of the updates substantially. Figure 4 shows an example of methods that use SessionState.


Figure 4

ASP.NET uses client cookies to uniquely identify sessions for SessionState so in order to use this feature you’ll need to do some work on the client. Within .Net it is very simple, we just need to create a new CookieContainer object to hold the cookies received from the service. Here is the client code used to do this.

 myService.CookieContainer = New System.Net.CookieContainer

While using SessionState can greatly improve performance it does “bend” the rules of Service Orientation regarding services being stateless. It’s also important to remember that not all clients will be able to accept your cookies. The performance increase however can be substantial and so with some caveats I think it makes sense to use.

Caveat 1: Any WebMethod that uses Session state must have a corresponding stateless version.

Caveat 2: For clarity you should name your stateful methods in a way that lets the client developer know that the use of SessionState is available.

3. Not Enough Bang for the Buck

If you personally had to follow on foot the path that your web service requests make across the company or across the world, one thing is certain; you’d only want to make the trip once. This is the same reason we make a list before going to the grocery store instead of making a trip for each individual item. There is always an expense of decreased performance or increased network traffic involved with a request that crosses physical boundaries.

Your web services should be designed to maximize the amount of work performed with each request. Make sure that the functionality you are offering is worth the time and effort the client had to go to in order to get the request to you in the first place. As an example, let’s build on our stock service.

You have probably seen demos that show how easy it is to send a stock symbol and receive a current market price. But what if you want to look up the price for ten stocks at a time? Using the demo version of the web service you would make ten trips to the server, wherever it may be. Would you want to walk that route?

For better performance, consider combining those smaller requests into a larger single request. In the case of stock symbols it’s fairly simple to combine the incoming symbols into an array of strings and return an array of Quotes from the method. Figure 4 shows this implementation of the GetQuotes method.


Figure 5

In more complex cases however, your services can begin to resemble a request-broker pattern and in fact many web services are built this way. Each request contains one or more smaller requests. The return values are then aggregated into a single response and returned to the client. A word of caution though, this can quickly escalate to a service with an interface that is so generic that it basically receives and sends any message. Once again we reach a situation where the client application is unable to create a useful proxy and is dependent on external documentation for interoperability. Figuring out how to balance request aggregation for performance with the increased complexity is just one of the jobs of an application architect and can only be determined on a case by case basis.

4. Using Web Services for Data Access

This mistake comes from a fundamental misconception about Web Services. Many architects and developers tend to see Web Services as a means to share data. The confusion is understandable; Microsoft itself muddies the waters with “enhancements” like the new feature in SQL Server 2005 that allows stored procedures to be accessed as Web Services with a few simple mouse clicks. This makes for great demos but bad application design.

Web Services don’t simply provide access to data; they provide access to an organization’s proprietary business knowledge. Organizations of all sizes, from departments to whole corporations, are defined by their business expertise. You don’t go to Starbucks for your banking needs and Bank of America doesn’t serve lattes. But organizations often want to share their expertise with other organizations. Starbucks might ask Bank of America to validate a credit card purchase for one of their lattes. This sharing of business knowledge means that Starbucks doesn’t have to reinvent how credit cards are processed and can concentrate on making coffee drinks.

How do organizations implement their business expertise? One way is by developing custom applications that enhance, improve on, or automate the use of that expertise. This is where web services and Service Orientation come in; by providing access to those applications to other organizations they are in effect sharing their expertise.

Perhaps the best example of a web service exposing functionality and not data is Google’s Web Service for searching web pages. How useful would the service be if it only returned the data, in this case information about millions of web pages, and you had to search through them yourself? Google has leveraged their extensive knowledge of how to search the web and that is where the value of their web service comes from, not their data.

When developing your web services, remember that what consumers of your service want is your business expertise not just data. You should question any web service method that merely queries and returns data. It most likely means that you are putting business logic on the wrong side of the service and forcing your consumers to reinvent your business expertise.

5. Trusting the Client Application

A Web Service’s responsibility goes beyond simply allowing access to business expertise. It’s also responsible for protecting the business and the integrity of its data. Many times a web service is developed at the same time as the user interface that will consume it. The web service acts as a “back end” to the application and often security is left to the UI. If security is applied only to the user interface side of the application you leave your web service vulnerable to attack and your business integrity in jeopardy.

The key is to break apart, both in your thinking and in design, the security of the user interface from the security of the Web Service. Each piece requires the proper application of security techniques including authentication, authorization, data encryption, etc. Keep in mind that other applications built by other organizations will be using your “back end” so you should make sure it’s covered, so to speak.

Security is a huge topic and beyond the scope of this article but here are some key points to keep your eyes open for.

  • You should assume that you cannot trust the data that you receive as input to the web methods. Web Services are hosted in ASP.Net and are therefore susceptible to the same kinds of attacks as any ASP.NET application including SQL Injections, Denial of Service, Replay Attacks, etc. Fortunately you can employ many of the same countermeasures to defend your service from these attacks.
  • The data being returned also needs to be protected. If you’re concerned about the integrity of the data as it passes through the network, the easiest way to protect it is to use SSL to encrypt the data between the client and server. You can also alleviate some of the threat of SQL Injections by not returning dynamically defined objects like Datasets and XmlDocuments.
  • Auditing is an important and often overlooked security feature. By building in the ability to track web service usage you enable both tracking of access violations and the ability to respond to attacks as they happen. Clear data violations could initiate a message to an administrator or lock out a user’s access to the service. Denial of Service attacks can be eliminated by instituting throttling mechanisms based on usage.

Architecturally, the key to avoiding security problems after a web service is deployed is to design security in from the very beginning. Don’t let yourself be fooled into thinking that securing the client is sufficient.

Conclusion

Web Services provide an unprecedented improvement in how applications are built across physical and organizational boundaries. Visual Studio.Net and the .Net Framework have made developing web services simple and easy, even bad ones. Architecting your services to avoid these common mistakes will ensure that your organization gets the most from Web Services.

Authors

Paul Ballard is a MCSD, MCAD, and MCSE certified consultant and the President of The Rochester Consulting Partnership, Inc. He has more than 15 years of experience designing and building client/server and web based distributed applications and is currently specializing in Microsoft's .NET technologies as a consultant, speaker, and trainer. Paul is also a volunteer with INETA and an editor for TheServerSide.NET.

News | Blogs | Discussions | Tech talks | White Papers | Downloads | Articles | Media kit | About
All Content Copyright ©2007 TheServerSide Privacy Policy
Site Map