There are many reasons to service-enable an application, from providing an integration to supporting new client types (such as mobile apps). If it’s a layered application with a message-based architecture, then the battle is half won. However, there are pitfalls to avoid, such as having the internal message format exposed to external consumers.
Message and data contracts will likely change with each release as new features are added and old ones tweaked to respond to evolving business needs. This works when all the components using those contracts are built and deployed simultaneously. Once that condition no longer applies, then the schema defining messages and payloads for the external consumers must become invariant. The alternative is attempting to coordinate synchronized releases between two or more applications. This is difficult enough with two internal teams, crossing organizational boundaries can make it truly painful.
Having parallel sets of message and data contracts for internal and external consumers (internal and external being relative to the application, not the organization) allows for the internal schema to evolve while the external schema remains static. Another advantage is that the external schema can be tailored to just the functionality to be exposed. The rub is that now you have to take messages and payloads that come into the service in an external format and transform them to the internal format used by the business layer.
An extremely flexible way to handle message transformation is via serialization and XSLT. Unfortunately, to obtain the flexibility, a measure of performance must be traded. If the service operates asynchronously, then that trade-off will most likely be the optimal one. However, synchronous services, particularly those with high traffic, may find the overhead of this method to be too much. For those situations, a code-based translation approach may give the best performance (albeit sacrificing flexibility).
Having chosen a code-based approach to message transformation, the next question is how best to implement it. Common concerns will be avoiding duplication of code and dependency management. At first glance, it would appear to work if you take the internal messages and add constructors that take the external message as a parameter as well as methods that output the external message. This centralizes the translation function to one or two methods that are co-located with the object to be translated to and from. It also introduces a new dependency to each and every assembly using the internal messages (assuming the external messages are reside in their own assembly). Clearly, this is not the manner in which to implement code-based transformation.
One method to avoid both duplicate code and dependency proliferation is to create static methods on classes that reside in an assembly separate from both the internal and external schema. The translation assembly then need only be referenced by the service layer which is the only one needing its services. While this can be done via a utility class (a la System.Convert), a more intuitive route is to set up extension methods. Extension methods are a bit of syntactic sugar added in version 3.0 of the .Net Framework that allow you to create static methods that appear to be instance methods of the type they extend. This provides centralized code without propagating dependencies unnecessarily and has the advantage of a cleaner syntax.