Because web services have received so much publicity, there are a lot of different ideas and
Web services are all about exposing data or functionality to unknown consumers on unknown hardware, written in unknown tools or languages. They're all about providing access to data and functionality in such a way that
Our ProjectTracker application has no need for web services
, because if we do any network communication, we're using the more efficient and powerful remoting technology. However, it's quite possible that our application's data or functionality could have value to other applications within our organization, or perhaps to our business
Some people believe that every logical tier in an application should be exposed via web services. This would allow a consumer to use a web service to retrieve or update data directly from the database, or to call middle-tier business objects, or maybe even to call UI functionality. In our five-tier logical model from Chapter 1, the result would look something like Figure 10-5.
Figure 10-5: Exposing a service from every tier in our application
The primary rationale for this approach is that we would use web services for all interaction with each tier of the application, thus gaining reuse. This sounds attractive on the surface, but it gets ugly very quickly.
Consider what happens to our application if we allow just any consumer to interact directly with the database via web services. Our data has rulesvalidation, security, and so forththat must be enforced. If a consumer can call a web service to update data in the database, then the database itself must have all the business rules available. Typically, this would mean writing all our business logic in something like T-SQL, which isn't the most productive or
Remember that we can't predict what kinds of consumers will be created in the future. Anywhere that we allow these unknown consumers to access our code, we must be defensive. We must assume that they will introduce
I'm somewhat adamant on this point, having been the victim of exposing procedures to unknown
What this really means is that our application architecture collapses into something like Figure 10-6.
Figure 10-6: Accessing the data through a web service
Our UI becomes just another client of the database server, where all the business logic and data management occurs.
We've been here before with 2-tier client-server applications, in the early to mid-1990s. Then we learned that if the only place where the business logic resides is the database, our user interface has to accept virtually any user input, and then send it to the database to find out whether what the
Instead of the approach presented in the previous section, the way to view web services is that they provide "just another interface" to our application. We can tie this idea back to our n-tier model from Chapter 2 as shown in Figure 10-7.
Figure 10-7: N-tier logical architecture with a
Notice that the web service and the consumer have clearly defined roles in this model: The consumer has become responsible for handling presentation and any other details of that
As always, it's for the UI tier to interact with the business logic, and for the Data Access tier to retrieve, process, and update data on
By taking this view of web services, we provide access not only to our data, but also to the combination of data and functionality within the context of our existing application. This is much more powerful, because it means that we automatically gain access to all our existing business logic, including validation, manipulation, security, and so forth. If another application wants to use our data, we want to perform security checks to see if that's OK. If another application wants to update our data, we want to perform security and validation checks, and apply any other business processing or rules.
The end result is that we'll write a set of web services that provide the same basic functionality as our Windows Forms or Web Forms interfaces, but without any consideration for the presentation. The web services code will interact with our existing business objects to retrieve, manipulate, update, or delete data. Since our objects provide not only the data, but also all
Perhaps the most important thing to remember about web services is that after we publish a web service and consumers start using it, the web-service interface can no longer be changed without breaking those consumers. In other words, those consumers may no longer be able to use our web service once the interface changes.
This is the same issue we faced with COM components: After you publish the interface to a component (or a web service), you can't change it without risking compatibility issues.
For this reason, we have to view the interface of each web-service method as a contract. Once we publish the web service, the contract is finalized, and we can only change it by paying up on the huge penalty clause built into that contract. In our case, the penalty clause
With web services, this issue is
Once it's exposed from our server, almost any programmer out there might decide to use it.
If we're not careful, the use of web services can make our overall application architecture very fragile. A change to our application can have a nasty ripple effect throughout our organization, or those of our partners or our customers. Because of this intrinsic fragility, we must be incredibly careful to separate the interface exposed by our web services from the underlying application. We want to be able to change, enhance, and maintain our ProjectTracker application over time, while at the same time minimizing the possibility that we'll break existing web-service consumers.
This is another reason why exposing every tier of our application via web services would be
At heart, a web service is just a collection of
A very easy way to define this data contract clearly is to use struct or class types in our web-service code. When we define a public struct in a web service, that data structure is exposed as part of our SOAP interface. This means that any consumer has easy access to the specific layout of the data structure we've defined.
Tools such as VS .NET take this data structure definition and use it to create consumer-side proxy classes that mirror the data structure automatically. This makes it very easy for the consumer developer to format data that will be sent to our web service properly, and to understand any complex data that our web service returns to the consumer. While we might use other techniques (such as an XML document) to transfer complex data, the use of a
or class provides the most automated and
Now that we've discussed some of the