Freigeben über


The “Service Interface” Pattern

I am constantly surprised when speaking with people how few have heard of or use the “Service Interface” pattern. It is actually a very straightforward pattern, is very little work to use, but brings such practical, quantifiable, visible, benefits I think it has to be one of my all time favourites. The Web Service Software Factory embodies a particularly good implementation of the pattern, too, so be sure to check that out. In fact, I’d go so far as to say that the easiest way to get familiar with this pattern is to read this post (obviously J) and then try the factory.

There’s already a bunch of documentation out there, including the pattern description on MSDN (although the corresponding implementation advice is a little dated due to the advent of things like WCF). The Web Service Software Factory documentation also describes the pattern, adding some more information and a sample to the MSDN docs.

The basics

What on earth is this pattern then? Well basically it is there to keep the “surface area” of a web service independent from the Business Logic. In exactly the same way as you would partition your User Interface from your Business Logic, it is wise to partition your Service Interface.

Separating these concerns means that your logic can evolve in implementation without breaking consumers of your service (remember that contracts between services are quite brittle in many cases), and also to evolve the communication mechanisms and formats your service uses without affecting your logic. Makes a lot of sense, huh?!

The Service Interface is also the ideal place to do things like message logging, exception shielding, versioning, and so on. All of these concepts are highly recommended for consideration before you deploy the first version of your service.

Pattern Components

There are a number of components that work together to form a well structured Service Interface. These components are depicted below;

Service Interface layering

I’m sure you’ve noticed that I don’t like to draw and talk too much without dropping down to see what this really means in code. So taking each component, one at a time, let’s see what they are, what they do, and what the code looks like. I’ll use WCF in this example, but the sample concepts can apply to other technologies.

Data Contracts

Data Contracts are the reusable entities used in service communications. They are similar to business entities, but are specifically used for over-the-wire transmission. Think of similarities to how Fowler’s description of Data Transfer Objects is implemented.

[DataContract(

   Name="Employee",

   Namespace="https://samples.microsoft.com/contracts/2008/08")]

public class Employee

{

    [DataMember]

    public string Name { get; set; }

    [DataMember]

    public int PayrollNumber { get; set; }

}

This shows a simple Data Contract. Note that this is an entity – all the data it contains is intrinsically related, in that it describes properties of an Employee. The DataContract and DataMember attributes are used to decorate the class for the DataContractSerializer’s benefit.

Do also pay attention to the fact that I’ve used the Namespace parameter of the DataContract attribute – this is an absolutely key step in ensuring your versioning strategy is up to scratch. I should really have also implemented IExtensibleDataContract, as per Craig’s post on Versioning WCF Services. I won’t cover this in detail but do make sure you read up on this before diving in.

Message Contracts

So Data Contracts define entities – but our service doesn’t deal in entities! It deals in messages. Therefore Message Contracts group together Data Contracts to form meaningful and useful messages.

Usually each operation (i.e. method on a service) has two Message Contracts – a Request and a Response. One Way operations obviously have no Response message, but you get the picture!

[MessageContract(

  IsWrapped=true,

  WrapperName="AddEmployeeRequest",

  WrapperNamespace="https://samples.microsoft.com/contracts/2008/08")]

public class AddEmployeeRequest

{

    [MessageBodyMember]

    public int DepartmentIdentifier { get; set; }

   

    [MessageBodyMember]

    public Employee Employee { get; set; }

    [MessageBodyMember]

    public Employee Manager { get; set; }

}

[MessageContract(

  IsWrapped=true,

  WrapperName="AddEmployeeResponse",

  WrapperNamespace="https://samples.microsoft.com/contracts/2008/08")]

public class AddEmployeeResponse

{

    [MessageBodyMember]

    public bool Success { get; set; }

    [MessageBodyMember]

    public string FailureMessage { get; set; }

}

Here we see I’ve introduced an “AddEmployee” operation that our service will provide. I always use the “Request” and “Response” naming suffix convention to ensure that the intended use of these messages is clear. Message Contracts are also not reused like Data Contracts are; they are inextricably bound to an operation, and exist purely to define that operation and to allow versioning strategies to exist.

Note that we use the MessageContract and MessageBodyMember attributes to decorate our contract, and that again I have used the Namespace parameter to help with versioning. I always use “IsWrapped=true” to ensure maximum compatibility (see Using Message Contracts).

Members of the Message Contract can be either Data Contracts or primitive types – the example shows the use of both our Employee contract and an Int32.

Service Contract

The Service Contract brings together our Message Contracts (and therefore implicitly our Data Contracts) to use them to define operations, and to group operations together to form a service.

[ServiceContract(

  Namespace="https://samples.microsoft.com/contracts/2008/08")]

public interface IEmpoyeeManagement

{

    [OperationContract(

    Action="https://samples.microsoft.com/contracts/2008/08/ É

  IEmployeeManagement/AddEmployee")]

    AddEmployeeResponse AddEmployee(AddEmployeeRequest request);

}

Note that in this case we’re using a .NET interface, not a class. We’re also using the ServiceContract and OperationContract attributes to decorate the interface. The Namespace and Action parameters to these attributes are used for versioning as usual.

Here you can see that my Request and Response messages are tied together by the Operation Contract definition for AddEmployee.

Service Configuration

The Service Configuration consists of many different things. I would like to define it as things that can be added to a service to customise the behaviour without requiring code or contracts to be changed... but unfortunately that isn’t quite true. For example, changing the InstanceContextMode can have a big effect on how you write your service. I guess this means that some specific areas of configuration and implementation are actually quite closely coupled, for good reason.

Anyway, configuration of a service includes things like the web.config settings (under <system.serviceModel>), and the use of the ServiceBehavior attribute. My service is so basic all I have in configuration is the default WCF web.config settings, so I’ll not bore you with that here!

Service Implementation

Well this one is pretty obvious, right? This is the meat of my service – the point of all these contracts, right? It’s the logic?

Nope.

I don’t mean to be so ruthless with this statement, but I just think it is important to understand. A service implementation is still part of the Service Interface – and it is purely responsible for translating between wire-format entities and business entities, maybe applying custom authorisation, message logging, exception shielding, and so on. It is almost an “adapter” layer that maps incoming messages onto the correct business logic – I firmly believe a service implementation should be very thin as a result of this, delegating most work to the business layer. The service implementation is not the business logic itself.

Let’s see a simple example implementation then;

public class EmployeeManagementService : IEmpoyeeManagement

{

    public AddEmployeeResponse AddEmployee(AddEmployeeRequest request)

    {

        try

        {

            ITranslator<Employee, Person> translator =

                Container.Get<ITranslator<Employee, Person>>();

            Logic.SavePerson(

                translator.Translate(request.Employee),

                translator.Translate(request.Manager),

                request.DepartmentIdentifier);

            AddEmployeeResponse response = new AddEmployeeResponse();

            response.Success = true;

            return response;

        }

        catch (BusinessLogicException exception)

        {

            AddEmployeeResponse response = new AddEmployeeResponse();

            response.Success = false;

            response.FailureMessage =

                ErrorMapper.SanitiseErrorMessage(exception);

            return response;

        }

        catch (Exception exception)

        {

            SystemFailure failure =

                ErrorMapper.SanitiseFailure(exception);

       throw new FaultException<SystemFailure>(failure);

        }

    }

}

We can see our service implementation is a class that implements our service contract, and there is very little else of note other than the method code itself. So let’s inspect the method code and see what we find.

Firstly we have some entity translation. It is really common for a service implementation to need to translate from a Data Contract to a Business Entity, and therefore a simple yet consistent approach to this has been born. Consider the following implementations;

public interface ITranslator<From, To>

{

    To Translate(From from);

}

public class EmployeeToPersonTranslator :

    ITranslator<Employee, Person>,

    ITranslator<Person, Employee>

{

    public Person Translate(Employee from) ..

    public Employee Translate(Person from) ..

}

These translators can easily be registered with a Service Locator (or we could use Dependency Injection or Dependency Resolution) as in my example, and retrieved with a call to a container.

Next we see our service implementation calls into some business logic, passing in translated entities and any additional data from the request message that is needed. Finally it constructs a success message and passes it back.

The other interesting part of this code is what happens in event of an error. My implementation is primarily designed to demonstrate a few different approaches, but the important point is that no error is returned to the caller without being “sanitised” first – i.e. I am applying the concepts of Exception Shielding. This ensures private data about my service (for example connection strings) is never exposed to the caller.

I’ve shown a few different approaches – using a return value in the response message, or using a Fault Contract (just a Data Contract used to communicate a fault) by throwing a new FaultException<T>. Fault Contracts should really be used in WCF if there is an unexpected error, but I do think there are some valid circumstances to use a “roll your own” response message; perhaps this is a topic for another post.

One point to note is that using this Fault Contract requires me to decorate my service contract with a FaultContract attribute;

[ServiceContract(

  Namespace="https://samples.microsoft.com/contracts/2008/08")]

public interface IEmpoyeeManagement

{

    [FaultContract(typeof(SystemFailure)]

    [OperationContract(

    Action="https://samples.microsoft.com/contracts/2008/08/ É

  IEmployeeManagement/AddEmployee")]

    AddEmployeeResponse AddEmployee(AddEmployeeRequest request);

}

Summary

Well that’s it – I hope this has helped you see how Service Interface fits together and what some of the benefits are. I’ve found that this approach helps with versioning, but also it helps to encourage a message-exchange approach to design instead of RPC (Remote Procedure Call).

What I mean by this is that services become designed to have course-grained interfaces, avoiding chatty calls. RPC is often seen like Java’s RMI – just calling methods on an object that happens to be physically located somewhere else – and this leads to forgetting about the costs of crossing service boundaries. Defining Data Contracts helps maximise reuse, and defining Message Contracts helps decrease granularity.

So now you love Service Interface just as much as I do, have a read of Don’s post regarding Message Contracts, and see what you think. I’m a firm believer in always using Message Contracts as I’m sure is obvious from this post, but make up your own mind.

Comments

  • Anonymous
    August 31, 2008
    Good stuff. I am new to WCF but this gives me a nice picture of how this stuff should work.

  • Anonymous
    June 16, 2009
    Sounds like Remote Facade to me http://www.martinfowler.com/eaaCatalog/remoteFacade.html Although it's just seperation of concerns in use. Having suffered at the hands of mass potato printed exception blocks on a collection of remote facades I suggest you look at moving a lot of that to aspects too. Regards Ed

  • Anonymous
    June 16, 2009
    @ Ed, you're absolutely right - it is indeed very similar to remote facade, but I think it has evolved to encapsulate knowledge about service versioning, etc. To quote the Service Interface pattern docs on MSDN; "Service Interface is a specific type of Remote Facade adapted for use in service-oriented architectures." So I guess that means we're talking the same language! As for exception handling in an aspect, I'd likely agree with you - in particular the Enterprise Library's exception handling app block has a nice Exception Shielding approach based on interception (http://msdn.microsoft.com/en-us/library/cc309233.aspx), and I am a big AOP believer... but having said that, I by no means think it is essential, and I'd rather keep the sample free from "noise" if you like. Do you have a preferred framework or approach for applying exception handling aspects? Just curious about people's experiences with different approaches. Simon