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 Chapter 2, 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. This, 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 you can address 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 assembly 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 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,
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";
}
}
Note
Since the client can never use the service class directly and must always go through a proxy, using explicit interface implementation is less important in WCF than it is in regular .NET programming.
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 both consume it independently of the class and have other
classes implement it.
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 can 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
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. 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 Chapter 2.
Get Programming WCF Services, 3rd 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.