In WCF, all services expose contracts. The contract is a platform-neutral and standard way of describing what the service does. WCF defines four types of contracts:
- Service contracts
Describe which operations the client can perform on the service. Service contracts are the subject of the next chapter, but they are used extensively in every chapter in this book.
- Data contracts
Define which data types are passed to and from the service. WCF defines implicit contracts for built-in types such as
int
andstring
, but you can easily define explicit opt-in data contracts for custom types. Chapter 3 is dedicated to defining and using data contracts, and subsequent chapters make use of data contracts as required.- Fault contracts
Define which errors are raised by the service, and how the service handles and propagates errors to its clients. Chapter 6 is dedicated to defining and using fault contracts.
- Message contracts
Allow the service to interact directly with messages. Message contracts can be typed or untyped and are useful in interoperability cases when another party has already dictated some explicit (typically proprietary) message format. That, however, is by no means the usual case for common WCF applications, so this book makes no use of message contracts. Unless you are required to leverage the flexibility, power, and extensibility of message contracts, you should avoid them, as they add no value but do add complexity. In many cases, the desire to use message contracts indicates a need for a custom application context, which can be addressed using custom headers (a useful alternative technique used throughout this book). For more on message headers, see Appendix B.
The ServiceContractAttribute
is defined
as:
[AttributeUsage(AttributeTargets.Interface|AttributeTargets.Class, Inherited = false)] public sealed class ServiceContractAttribute : Attribute { public string Name {get;set;} public string Namespace {get;set;} //More members }
This attribute allows you to define a service contract. You can apply the attribute on an interface or a class, as shown in Example 1-1.
Example 1-1. Defining and implementing a service contract
[ServiceContract]
interface IMyContract {[OperationContract]
string MyMethod(string text); //Will not be part of the contract string MyOtherMethod(string text); } class MyService : IMyContract { public string MyMethod(string text) { return "Hello " + text; } public string MyOtherMethod(string text) { return "Cannot call this method over WCF"; } }
The ServiceContract
attribute maps a CLR interface
(or inferred interface, as you will see later) to a technology-neutral service contract.
The ServiceContract
attribute exposes a CLR interface
(or a class) as a WCF contract, independently of that type's visibility. The type
visibility has no bearing on WCF, because visibility is a CLR concept. Applying the
ServiceContract
attribute on an internal interface
exposes that interface as a public service contract, ready to be consumed across the
service boundary. Without the ServiceContract
attribute, the interface is not visible to WCF clients, in line with the service-oriented
tenet that service boundaries should be explicit. To enforce that tenet, all contracts
must explicitly opt in: only interfaces (or classes) decorated with the ServiceContract
attribute will be considered as WCF contracts;
other types will not.
In addition, none of the members of the type will ever be part of the contract when
using the ServiceContract
attribute. You must
explicitly indicate to WCF which methods to expose as part of the WCF contract using the
OperationContractAttribute
, defined as:
[AttributeUsage(AttributeTargets.Method)] public sealed class OperationContractAttribute : Attribute { public string Name {get;set;} //More members }
You can apply the OperationContract
attribute only
on methods, and not on properties, indexers, or events, which are CLR concepts. WCF only
understands operations—logical functions—and the OperationContract
attribute exposes a contract method as a
logical operation to perform as part of the service contract. Other methods on the
interface (or class) that do not have the OperationContract
attribute will not be part of the contract. This enforces
explicit service boundaries and maintains an explicit opt-in model for the operations
themselves. In addition, a contract operation cannot use object references as parameters:
only primitive types or data contracts are allowed.
WCF lets you apply the ServiceContract
attribute
on an interface or on a class. When you apply it on an interface, some class needs to
implement that interface. In general, you use plain C# or VB to implement the interface,
and nothing in the service class code pertains to it being a WCF service:
[ServiceContract]
interface IMyContract {[OperationContract]
string MyMethod( ); } class MyService : IMyContract { public string MyMethod( ) { return "Hello WCF"; } }
You can use implicit or explicit interface implementation:
class MyService : IMyContract
{
string IMyContract
.MyMethod( )
{
return "Hello WCF";
}
}
A single class can support multiple contracts by deriving and implementing multiple
interfaces decorated with the ServiceContract
attribute:
[ServiceContract]
interface IMyContract
{
[OperationContract]
string MyMethod( );
}
[ServiceContract]
interface IMyOtherContract
{
[OperationContract]
void MyOtherMethod( );
}
class MyService : IMyContract,IMyOtherContract
{
public string MyMethod( )
{...}
public void MyOtherMethod( )
{...}
}
There are, however, a few implementation constraints on the service implementation class. You should avoid parameterized constructors, because WCF will only use the default constructor. Also, although the class can use internal properties, indexers, and static members, no WCF client will ever be able to access them.
WCF also lets you apply the ServiceContract
attribute directly on the service class, without defining a separate contract
first:
//Avoid
[ServiceContract]class
MyService { [OperationContract] string MyMethod( ) { return "Hello WCF"; } }
Under the covers, WCF will infer the contract definition. You can apply the OperationContract
attribute on any method of the class, be
it private or public.
Warning
Avoid using the ServiceContract
attribute
directly on the service class. Always define a separate contract, so that you can use
it in other contexts.
You can and should define a namespace for your contract. The contract namespace
serves the same purpose in WCF as it does in .NET programming: to scope a type of
contract and reduce the overall chance of a collision. You use the Namespace
property of the ServiceContract
attribute to provide a namespace:
[ServiceContract(Namespace = "MyNamespace")] interface IMyContract {...}
Unspecified, the contract namespace defaults to http://tempuri.org.
For outward-facing services you would typically use your company's URL, and for intranet
services you can use any meaningful unique name, such as MyApplication
.
By default, the exposed name of the contract will be the name of the interface used.
However, you can use an alias for a contract to expose a different name to the clients
in the metadata, by using the Name
property of the
ServiceContract
attribute:
[ServiceContract(Name = "IMyContract")] interface IMyOtherContract {...}
Similarly, the name of the publicly exposed operation defaults to the method name,
but you can use the Name
property of the OperationContract
attribute to alias it to a different
publicly exposed name:
[ServiceContract]
interface IMyContract
{
[OperationContract(Name = "SomeOperation"
)]
void MyMethod(string text);
}
You will see a use for these properties in the next chapter.
Get Programming WCF Services, 2nd Edition now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.