Decisions to Make

Applies to: Windows Communication Foundation

Published: June 2011

Author: Greg Cowin

Referenced Image

This topic contains the following sections.

  • Decision: WSDL First or Code First
  • Decision: How Will You Design and Organize Your Services?
  • Decision: How to Communicate Errors
  • Decision: Use a Security Token or a User name and Password
  • Decision: Is the Security Token Embedded in the SOAP Header or Is It an Explicit Parameter?
  • Decision: Whether to Use XML for Parameters and Results
  • Decision: How to Avoid Breaking Existing Consumers

Many existing WCF services are inconsistently designed, difficult to use, and have security and operational issues. One way to prevent these problems is to make the right decisions before you begin a WCF project. WCF allows you to connect systems in many different ways. This article, which presents a WCF decision framework, will help you to select the options that are best for you, and to deploy a well-designed set of services.

A decision framework presents a simple, yet potentially powerful, sequence of decisions to make and actions to take. Use the framework that is presented in this article as a starting point for your own. You and your team can provide additional alternatives, and add new elements, as you evolve your portfolio of services.

Hopefully, you can discuss these decisions and actions with your team, and pick the alternatives that help you to converge on the right solution. WCF is the best framework for implementing SOA (Service-Oriented Architecture) based services. By making the right decisions, you can create a flexible and adaptable service that can be used in the enterprise, for mobile applications, and as integration points for partners and customers.

In a competitive world, you need to make good decisions and do the right things.

This section discusses the decisions you and your team should make when you begin a WCF project. Alternatives and recommendations are included to help you see the different possibilities, and to choose the options that suit your requirements.

Each decision has the following sections:

  • Description - This is a description of the problem.

  • Alternatives - These are some of the possible solutions to the problem, with their pros and cons.

  • Recommendation - This is the recommended approach.

Be sure to talk over each alternative with your team. Try to consider alternatives that are not included here. If you follow this procedure, then whatever you decide will be easier to follow and implement, even if not everyone agrees. At least everyone will be able to accept and understand the decision because they all took part in the discussion.

Decision: WSDL First or Code First

Description

The initial question is whether you should first create the Web Service Description Language (WSDL) and let it generate the service contract interfaces, or should you first code the service contracts, and let them generate the WSDL. WCF supports both options. If you have already developed a WCF project, then you may have a preference, and can probably omit this step. This decision often becomes a point of discussion for new WCF projects.

Alternatives

Here are the advantages and disadvantages to each approach.

  • WSDL First – In WSDL-first development, you create the WSDL, and then use it to generate the code for the service contracts. In the past, with the ASMX framework, the SDK (Software Development Kit) provided a tool, Wsdl.exe, which accepted a WSDL file and generated stubs for the service. Today, with WCF, use the Svcutil.exe tool. It generates the WSDL based on service and data contracts that you specify in XML. For a good overview of WSDL-first development, see the MSDN blog post at https://blogs.msdn.com/b/dotnetinterop/archive/2008/09/24/wsdl-first-development-with-wcf.aspx. Another useful article is "Schema-based Development with Windows Communication Foundation" at https://msdn.microsoft.com/en-us/magazine/ee335699.aspx.

    Pros

    The WSDL-first approach gives you precise control of the WSDL.

    Cons

    If you must create and edit large amounts of WSDL before you generate code,then the development velocity slows.

  • Code First - In code-first development, you begin with a service that has the appropriate ServiceContract, ServiceOperation, and DataContract attributes, and then generate the WSDL. Most WCF examples and tutorials use the code-first

    Pros

    The code-first approach is easier and faster than the WSDL-first approach. It isthe more accepted approach of the two, and there are more online resources available to help you.

    Cons

    The code-first approach gives you less fine-grained control of the WSDL.

Recommendation

Use the code-first approach, except when you must support a particular WSDL contract exactly. The rationale is that most people find it easier to write a five or six line service contract in C# than to write one hundred or more lines of obscure XML. There are tools available that can help you to code your service and data contracts. It is much more difficult to first specify the contracts in WSDL, and then generate and regenerate the representation. Instead, let Microsoft® Visual Studio®, or the .NET Framework SDK, generate the corresponding WSDL. In practice, most teams use the code-first approach for one reason — it is faster.

Decision: How Will You Design and Organize Your Services?

Description

How you design and organize your services is the most important decision in any WCF project. You need to know what each service will do, and you must know how to group those services into blocks and projects.

A service block (or service category) is a logical set of services that pertain to a particular area of the application, such as security, notification, scheduling, or accounting. You can assign the development of a service block to an individual or to the team. If you are only implementing one or two services, then how you group them may not matter. If you are developing services for an existing application, or if you are working with a large enterprise-scale system, then this decision is critical. The way that you partition services determines how easy it will be to support and deploy them, not only now, but also in the future. Here are some guidelines for partitioning services into service blocks.

  • Avoid a monolithic set of services in your projects.

  • Keep the service blocks loosely coupled by reducing the dependencies between them.

  • Partition services so that individuals or teams can work on different service blocks concurrently with help from loose coupling.

  • Make the consumption of these service blocks easy and logical.

  • Provide a documented service portfolio.

Alternatives

One way to approach the design and organization of services is to use the subject area as the driving principle. Another approach is to use scenarios as the driving principle.

Using Subject Areas

The subject-area approach starts with a logical set of service categories, and then defines services for each of the service categories. Logical categories or subject areas that are part of a schema are often good candidates for service categories. Vertical service blocks are frequently based on categories, or subject areas, in a database schema. Begin with the subject area, add the domain logic, and then expose a thin service layer that can be consumed. Follow these design steps for each service category:

  1. Use Unified Modeling Language (UML) models to define the services. Model them with stereotypes that are based on the subject or domain areas.

  2. Use these models, as well as scenarios and use cases, to drive the initial development of the services.

  3. Review the models with domain experts.

  4. Conceptually test the categories with scenarios and use cases.

  • When you review the initial results, ask yourself the following questions:

  • Does the subject area provide a logical block for some services?

  • Is the service block loosely coupled to other service blocks?

  • Does the service block constitute a logical collection of services?

  • Do the developers on your team understand why the services were partitioned into those service blocks?

Using Scenarios

Another approach is to use scenarios to drive the design of your services, and then to use logical areas to group those services. Just as test-driven development produces well-designed APIs, so does scenario-driven development produce well-designed service blocks.

Recommendation

Use subject areas for larger projects that have established schemas. It's always helpful if you have a good schema already in place. Scenarios are better suited to "greenfield" projects, where there are no constraints imposed by an existing application. Ultimately, keep it as simple as possible. It is important to get the design of services right. Services are not as forgiving, from a refactoring point of view, as other .NET development projects.

In addition, you can consider using a hybrid approach. Use the subject-area approach to develop a set of service categories from the top down. Then, develop the actual services from the bottom up; collaborate with the consumer of your services. Alternatively, you can use scenarios, use cases, or even user stories to drive the design of the services.

Decision: How to Communicate Errors

Description

It is important that you effectively communicate errors to a service's clients. Clients must know what action to take when there are failures and exceptions. If you do not make an actual decision on how to communicate errors, then the result will be a portfolio of services that have an inconsistent, or even a nonexistent, approach toward error handling.

This decision is a challenging one because it always involves multiple tradeoffs. For example, if you use the Simple Object Access Protocol (SOAP), you must determine whether your client supports SOAP faults, and if that client can turn SOAP faults into exceptions.

The two things that you can count on in a highly distributed computing environment are latency and failure. All errors, including application errors such as authorization, validation, and business rule errors, need to be communicated. You must provide clients with the information they need to recover from failure. If services communicate errors consistently, then it is easier for clients to provide a mechanism for recovery.

Alternatives

Two ways to communicate errors to clients are to use SOAP faults or to use result objects.

  • Using Soap Faults –A SOAP fault contains the fault type and the fault description.

    Pros

    One advantage to using SOAP faults is that the WSDL contains the type of fault that is declared in the service's interface definition. In other words, you formally specify the fault as a part of the WSDL. Another advantage is that some clients handle SOAP faults as exceptions, which is a better way to handle unexpected errors.

    Cons

    There are several limitations to SOAP faults. One is that not all clients support custom SOAP faults. Another is that SOAP faults depend on the SOAP model. For example, what if you decide to emit JavaScript Object Notation (JSON) by using WCF instead of by using SOAP objects? The faults do not work in the same way. Finally, clients in a browser do not know the error's actual status code and message because the browser hides them, unless it uses Silverlight 3.0 or greater.

  • Using Result Objects – If you use a result object to communicate errors, then create a data contract class for the result object, and use that class or a subclass, for all of the service operations' return values. For example, you can create a ServiceResult class and have every service operation return either a ServiceResult object or an instance of a class that derives from the ServiceResult class. The ServiceResult class communicates all exceptions except for timeouts and communication exceptions, which still arrive as SOAP faults. If you use result objects, you generally do not need custom faults because most of the result statuses are captured as a part of the ServiceResult. The following figure illustrates a class diagram of the ServiceResult class, with its possible result statuses.

    Figure 1: Design of a typical ServiceResult class

    Referenced Image

    Pros

    The advantages to result objects are that they are easy for clients to handle, theywill work with other service serialization behaviors, such as JSON, and they followa request/reply pattern. It works with SOAP-based and non-SOAP based services.

    Cons

    The disadvantage to result objects is that they are an outmoded way to handlefailures such as exceptions. Result objects go back to at least the C programminglanguage where almost every function returned a result code. Today, errorresults are usually communicated via exceptions.

Recommendation

Generally, use SOAP faults to communicate errors if your clients support them. Be sure to verify that assumption. Exceptions are certainly a more modern way to deal with unexpected errors. If you support technologies such as Silverlight 2 and other, older, types of clients, use result objects to communicate errors. Silverlight 3 and 4 support SOAP faults.

Decision: Use a Security Token or a User name and Password

Description

Service calls generally require that the caller of the service be authenticated. Most systems support only a few services that allow anonymous access. The implication is that you must provide some form of authentication. One choice is to use an authentication service that returns a security token after it validates the caller. Another choice is to pass a user name and password and authenticate them for every call.

Alternatives

Here are the considerations for security tokens versus user names and passwords.

  • Using Security Tokens - There are authentication services that return a security token after a caller is successfully authenticated. Subsequent calls to the service pass the security token. A security token generally expires in a short amount of time.

    This is probably the most commonly used approach today. A token service is required. Your team can write its own token service, or you can use a commercially off the shelf solution (COTS) such as the Active Directory Federation Service (ADFS).

    Pros

    The security token approach is consistent with current security standards, and is intended for modern and emerging technologies such as ADFS.

    Cons

    This approach requires a token manager or service.

  • Using User Names and Passwords - This approach passes the user name and password in each call to the service. An advantage to this approach is that it is totally stateless. However, it requires that every call be authenticated (make sure that the user name and password are correct).

    Pros

    This approach is stateless, and requires no token service.

    Cons

    There are several disadvantages. One is that each operation must authenticate the principal. Also, each operation requires the user name and password in order to perform the authentication. This approach is a bit outdated because it sends the actual password, which could be compromised at some point with a brute force attack.

Recommendation

Use a security token whenever possible. The authentication service provides you with a security token when you provide it with valid credentials. The security token, or identifier, will be stored with the security schema. You do need a centralized security token service. Security tokens are a more modern way to deal with authentication and they are designed to work with ADFS and other single-sign-on mechanisms.

Decision: Is the Security Token Embedded in the SOAP Header or Is It an Explicit Parameter?

Description

If you use security tokens for authentication and authorization, then you should decide if the token will be included in the SOAP header, or if it will be an explicit parameter in the call to the service.

Alternatives

Here are the considerations for placing a security token in the header, or making it a parameter in the service call.

  • Embedding the Security Token - The first choice is to embed the security token in the header of the SOAP envelope.

    Pros

    The advantage to this approach is that a handler can process every message to ensure that the principal associated with the security token in the header is valid.

    Cons

    The disadvantage to this approach is that anything that is in the SOAP header is really an embedded parameter. When other service behaviors are used such as JSON serialization, it is awkward and sometimes not possible for the client to process the header.

  • Making the Security Token a Parameter - The second choice is to make the security token a parameter. Typically, it is the first parameter in the service call.

    Pros

    This approach ensures that all of the parameters are explicit and clear to all consumers. It also works well with all types of clients and bindings.

    Cons

    One disadvantage is that you need to ensure that the token is included in the appropriate service calls. The other disadvantage is that each service operation must validate the security token.

Recommendation

Consider using the security token as a parameter. The essence of a service-oriented approach is to separate the interface from the implementation. Embedding the token within the header implies a particular implementation. For example, you might eventually deploy the service with another binding that does not have the concept of a header. This is true of JSON, which is widely used with mobile applications. However, if you are certain that you will only use SOAP, then you should embed the token in the header.

Decision: Whether to Use XML for Parameters and Results

Description

You can use XML-formatted strings for parameters and result objects. To do this, you pass a string parameter and parse it as XML within the application. This approach is fairly popular because it does not require you to update services and the associated WSDL when the schema of the XML data changes. Web service clients in Flash seem to have increased the use of this idiom. Some of the Flash controls, such as the tree control, require that parameters be given as XML strings.

Alternatives

The two choices are either to use XML, or to use data contracts and data members.

  • Using XML – Generally, developers who use XML as a parameter or a result pass it as a string.

    Pros

    The main advantage is that you do not have to change the WSDL when parameters and results change.

    Cons

    The disadvantages are that this is non-standard approach, and the client must parse the XML because it is not a part of the WSDL.

  • Using DataContract and DataMember – The alternative approach is to implement data contracts for every parameter and result by using the DataContract and DataMember attributes. For more information about how to implement a data contract, see "Using Data Contracts" at https://msdn.microsoft.com/en-us/library/ms733127.aspx.

    Pros

    This approach is the standard one, and a best practice. It also provides better performance. Finally, clients do not need to parse XML strings.

    Cons

    You must decorate classes that are used in parameters and results with the DataContract attribute, and class members with the DataMember attribute.

Recommendation

In reality, if you use XML as a parameter or result, you still must deal with a schema and its changes. You also have more complexity because you must manage the schema of the WSDL, as well as the XML schemas. It is an illusion to think that by using XML you avoid the issue of schema migration.

The recommendation is to use DataContract and DataMember attributes whenever possible. In almost every case, clients are better suited to this approach.

Decision: How to Avoid Breaking Existing Consumers

Description

You should avoid making changes to your services that break existing consumers. A breaking change includes any change to an existing service operation or data contract. Breaking changes also include changes to the binding. Breaking changes do not include adding a new service operation or a new data contract because the consumer will be unaware of them. It is true that some clients that use relaxed versioning allow optional data members to be added, but it is recommended to treat this as a breaking change unless you know that all of your clients have this capability. Service versioning may be necessary if you do make changes that break consumers. Note that, even if you control the deployment of the consumers, you still need to make sure that you do not break them if you deploy a major change to a web service.

Alternatives

Here are a few alternatives for dealing with breaking changes, and for versioning service contracts.

  • Deploy Services and Consumers Concurrently – If you control the deployment of all of the consumers of a service, you can generally avoid versioning by deploying the services and the consumers at the same time. Naturally, you must refresh the service references in all of the consumers, and resolve any issues before the deployment.

    Pros

    This approach avoids the overhead of creating new contracts or endpoints. It does not break existing clients.

    Cons

    In cases where you do not control the deployment of the consumer, the client application has no way to migrate to the updated contract. Also, there is no realistic way to support third-party consumers.

  • Create a New Contract – A second approach is to create a new contract that has a new name and namespace combination. Remember that the name and namespace identify the contract. You cannot change the contract without changing the client. A variant of this approach is to include the version number in the contract name.

    Pros

    This approach enables you to support multiple versions of a service that share the same codebase. It does not break existing clients.

    Cons

    There are two disadvantages. One is that you must duplicate some code in order to support multiple versions of the service. You also need to create data contracts for each version; otherwise, the new contract could make breaking changes to the data contracts too.

  • Create a New Endpoint - The last alternative is to change the contract, provide a different implementation of the service, and deploy it to a new endpoint.

    Pros

    A new endpoint enables you to support multiple versions of the service.

    Cons

    You must maintain a deployment for each version of the service that you support. This means that you must maintain at least two versions of the contract. The implication is that you must either branch your codebase, or maintain additional codebases.

    Another disadvantage is that all codebase branches and deployments must be updated whenever any external systems, such as databases, change. If older versions are still deployed, you must ensure that you do not make schema changes that break them. This is why you may need to branch the older codebases, as well as make sure that you keep the older versions up to date. All of this maintenance can make it difficult to avoid making breaking changes. You may have to carefully sequence the changes, both to the services and to the schemas. For more information, see "Service Versioning" at https://msdn.microsoft.com/en-us/library/ms731060.aspx.

Recommendation

If possible, avoid multiple versions of a service. If you do need multiple versions, consider giving each of them a new contract. Whatever you do, avoid breaking your service consumers.

Previous article: Validation, Part 2

Continue on to the next article: Actions to Take