In heterogeneous environments it is common for
systems to have difficulties communicating directly. Some may be using
the TCP as a transport protocol, while others may only be capable of
using HTTP over TCP, or even SOAP (over HTTP and TCP). Even when two
legacy systems use the same protocol, they might be using different
versions, which can result in the same communication-level
incompatibility.
A technique for overcoming these problems is via Protocol Bridging.
In essence, this pattern involves placing an intermediary in between
two pieces of software that converts between the incompatible protocols,
thereby enabling them to exchange data. As with Data Model
Transformation , applying this pattern will lead to increased development effort and increased performance overhead.
The Standardized Service Contract principle further helps establish the standardized interoperability on
the protocol level with the help of the Canonical Protocol
pattern, which requires that communication protocol (including protocol
versions) be regulated among services within the same service inventory
boundary.
Of course, this leads to the
question of which protocol to choose. The choice of protocol will be
dependent on the choice of service implementation medium. Currently
there are three common service implementation options:
components
Web services
REST services
The following sections explore the differences of each in relation to building services with WCF.
Web Service
A
Web service uses a WSDL definition and one or more XML schemas to
specify its interfaces. Its protocol is usually based on the use of SOAP
over HTTP. Figure 2 shows a Web service implemented in WCF with the IUserBankService interface and Figure 9.10 illustrates the DataContract for representing the User class.
As shown in the following example, the interface is created and annotated with the ServiceContract and OperationContract attributes.
Example 1.
[ServiceContract] public interface IUserBankService { [OperationContract] void CreateUser(Core.Models.User user); [OperationContract] Core.Models.User GetUser(Guid userId); [OperationContract] void ModifyUser(Core.Models.User modifiedUser); [OperationContract] void DeleteUser(Guid userId); }
|
The ServiceContract attribute indicates that it’s a WCF service and the OperationContract
attribute indicates that the method that is annotated with this
attribute needs to be exposed by the service. Note that these attributes
are used irrespective of the kind of service we’re creating with WCF.
The interface is then implemented in a class, as shown here:
Example 2.
public class UserBankService:IUserBankService { public void CreateUser(Core.Models.User user) { throw new NotImplementedException(); } public Core.Models.User GetUser(Guid userId) { throw new NotImplementedException(); } public void ModifyUser(Core.Models.User modifiedUser) { throw new NotImplementedException(); } public void DeleteUser(Guid userId) { throw new NotImplementedException(); } }
|
As you can see, no attributes
are used on the class as they were already used on the interface. To
make the service actually do something, we would need to populate the
method definitions with code.
Note
that we could have decorated the class and the methods in the class
with the WCF attributes. By instead decorating the interface, we have
applied the Decoupled Contract pattern by separating the service definition from its implementation.
Second, there is nothing in
our code so far that specifies that this should be a Web service. To
make it into a Web service, we can add a configuration. This next
example shows the relevant part of the configuration that implements
this service as an actual Web service:
Example 3.
... <system.serviceModel> <services> <service name="Core.Services.UserBankService"> <endpoint address="..." binding="basicHttpBinding" contract="Core.Services.IUserBankService"> ... </endpoint> </service> </services> ... </system.serviceModel> ...
|
basicHttpBinding is
what makes this service into a Web service, as it instructs WCF to use a
WS-BasicProfile Web service communication mechanism with HTTP as
transport and messages encoded as text/XML.
REST Service
When designing a service as a
REST service we can still use WCF and the resulting code is actually
quite similar to that of a Web service implementation. Figure 3 shows an interface that corresponds to the previous Web service example.
As with the Web service interface definition, the REST service interface is annotated with WCF attributes:
Example 4.
[ServiceContract] public interface IUserBankServiceRest { [OperationContract] [WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Xml)] void CreateUser(Core.Models.User user); [OperationContract] [WebGet(UriTemplate="users/{userId}")] Core.Models.User GetUser(string userId); [OperationContract] [WebInvoke(Method = "PUT")] void ModifyUser(Core.Models.User modifiedUser); [OperationContract] [WebInvoke(Method = "DELETE")] void DeleteUser(Guid userId); }
|
The ServiceContract and OperationContract attributes are still there, but we also added WebInvoke and WebGet
attributes. These attributes (originally introduced in .NET framework
3.5) are specific for a REST service implementation and specify
operation behaviors.
The WebInvoke
attribute makes it possible for methods to invoke using the HTTP
protocol. This attribute takes some arguments, and the most significant
of these is the method argument. The valid values of the method argument
correspond to the POST, PUT, and DELETE HTTP methods. The HTTP protocol
offers additional methods, but these are the only ones supported by the
WebInvoke attribute. (The WebGet attribute also allows you to specify that a method should be possible to invoke using HTTP GET.)
After creating the interface
we again need a class that implements it. Just as with a Web service, we
can use all the attributes directly on the class.
Component
Components
differ from Web service and REST service implementation options in that
they are more technology and platform specific, especially in relation
to transport protocols. A component is implemented in a certain language
and uses certain frameworks. Therefore, in order to use a component you
need to have access to the component technology locally.
Another
differentiator is that the service is not called remotely. Rather, you
instantiate a component locally and use its API, which is why components
are said to be more tightly coupled than Web services and REST
services.
In the following example we
can use the same class as we used earlier when we implemented a Web
service. Instead of calling it remotely as a Web service we use it as
follows:
Example 5.
UserBankService serviceAPI = new UserBankService(); serviceAPI.CreateUser(new Core.Models.User() { UserId = Guid.NewGuid(), Address = "MyAdress", FirstName = "John", LastName = "Smith", PhoneNumber = "0332133333", SocSecNumber = "730X29" } );
|
Another WCF Option: Named Pipes
When you develop services
in WCF you can also consider the use of named pipes as the transport
protocol. This option is similar to using a WCF library as a component
because you cannot choose the technology platform for the consumer
freely.
The benefit, compared
to the component option, is that a service exposed through named pipes
runs as an independent process. However, a service exposed using named
pipes can only be accessed when the service consumer is installed on the
same machine.
Access can be enabled by changing the binding of the service to NetNamedPipeBinding.
Dual Protocols with WCF
Although limiting service
interaction within a service inventory to one transport protocol is
desirable, it can sometimes introduce limitations that make some service
requirements hard to fulfill. There may be circumstances that warrant
the use of a secondary protocol to complement the primary protocol, as
per Dual Protocols.
This pattern is commonly applied when the primary protocol introduces
performance issues or when a new protocol is introduced as the primary
protocol and a period of transition is allowed for the migration of
services from the now demoted protocol (the secondary protocol) to the
new primary protocol.
WCF enables the application of Dual Protocols
by allowing additional endpoints to be added to services via
configuration with little or no change to existing code. Configuring a
new endpoint is a matter of adding a new address and binding—the ServiceContract part can be reused.