2.2 Contracts
2.1 Service Contract
In Windows Communication Foundation (WCF), the ServiceContract
attribute is used to define a service contract. A service contract in WCF specifies the operations that a service exposes and provides a way to describe how the service can be called and interacted with by clients.
1. Key Points about ServiceContract
1. Definition of Service Interface:
The ServiceContract
attribute is applied to an interface, which defines the methods that the service will expose to clients. These methods must be decorated with the OperationContract
attribute to be part of the service contract.
[ServiceContract]public interface IMyService{ [OperationContract] string SayHello(string name);}
2. Declarative Metadata:
By using ServiceContract
, you are providing metadata about the service that WCF uses to generate the necessary communication infrastructure, such as service endpoints, bindings, and contracts.
3. Configuration: The service contract is used in conjunction with other WCF configurations to set up how the service is hosted and how it communicates with clients. This is typically specified in configuration files or programmatically.
4. Data Contracts:
To define the data types that are exchanged between the service and clients, you also use the DataContract
attribute on classes and the DataMember
attribute on properties or fields.
2. Example of a Service Contract
Here’s a simple example of a WCF service contract:
using System.ServiceModel;
[ServiceContract]public interface ICalculatorService{ [OperationContract] int Add(int a, int b);
[OperationContract] int Subtract(int a, int b);}
- The
ICalculatorService
interface is marked with theServiceContract
attribute, indicating that it defines a WCF service contract. - The
Add
andSubtract
methods are marked with theOperationContract
attribute, indicating that they are operations that clients can invoke.
Implementing the Service Contract
To implement this contract, you create a class that implements the interface:
public class CalculatorService : ICalculatorService{ public int Add(int a, int b) { return a + b; }
public int Subtract(int a, int b) { return a - b; }}
In this implementation, the CalculatorService
class provides the logic for the operations defined in the ICalculatorService
contract.
2.2 Data Contract
In Windows Communication Foundation (WCF), a Data Contract is used to define the structure of data that is exchanged between a service and its clients. It specifies how data is serialized and deserialized, ensuring that both the service and client understand the format of the data being transferred.
1. Key Points about Data Contracts
1. Definition of Data Structures:
A Data Contract is applied to a class or struct and describes the data that will be transferred between the service and client. You use the DataContract
attribute to mark the class or struct, and DataMember
attributes to specify which members of the class or struct are included in the contract.
2. Serialization: Data Contracts define how data is serialized into XML or JSON (depending on the binding) for transmission over the network. This serialization is necessary because WCF needs a standardized way to represent data for communication.
3. Consistency: Data Contracts ensure that both the service and the client use the same data format. Any changes to the data contract in the service must be compatible with the contract expected by the client to avoid communication issues.
4. Optional and Required Members:
Data members in a Data Contract can be optional or required. By default, members are optional, and you can use the IsRequired
property of the DataMember
attribute to specify if a member is required.
2. Example of a Data Contract
Here is an example of how you define a Data Contract in WCF:
using System.Runtime.Serialization;
[DataContract]public class Person{ [DataMember] public string FirstName { get; set; }
[DataMember] public string LastName { get; set; }
[DataMember(IsRequired = true)] public int Age { get; set; }}
In this example:
- The
Person
class is decorated with the[DataContract]
attribute, indicating that it is a data contract. - The
FirstName
,LastName
, andAge
properties are decorated with the[DataMember]
attribute, indicating that these properties are part of the data contract and will be serialized/deserialized.
3. Using Data Contracts in Services
When defining a WCF service, you can use data contracts as method parameters and return values:
[ServiceContract]public interface IPersonService{ [OperationContract] Person GetPersonInfo(int id);}
In this service contract, the GetPersonInfo
method returns a Person
object, which is defined by the data contract.
4. Data Contract Considerations
- Versioning: If the structure of your data contract changes, you should consider how these changes might affect clients. Adding new members with default values is typically safe, but removing or renaming members can cause issues.
- Inheritance: Data Contracts support inheritance, allowing derived classes to be used with WCF services. Ensure that derived classes are also properly decorated with
DataContract
andDataMember
attributes.
Data Contracts play a crucial role in WCF by providing a way to define and control the structure of data exchanged between services and clients, ensuring compatibility and consistency in communication.
5. Private Members in DataContract?
In WCF, private members of a class cannot be directly passed using a Data Contract. The Data Contract mechanism requires that only public members (properties or fields) be included in the serialization process.
Here’s a breakdown of why this is the case and how you can work around it:
5.1 Why Private Members Aren’t Included
1. Serialization: WCF’s serialization process relies on accessing public members to convert them into a format suitable for transmission (like XML or JSON). Private members are not accessible during serialization because they are not part of the public interface of the class.
2. Data Contract Specification: The Data Contract model is designed to be explicit about what data is serialized and deserialized. By focusing on public members, WCF ensures that only the intended data is included in the contract.
5.2 Workarounds
If you need to include data that is not directly accessible through public members, you can use the following approaches:
1. Expose Data via Public Properties: Define public properties in your Data Contract class that internally access private fields. This way, you control the exposure of the data while still adhering to the Data Contract model.
[DataContract]public class Person{ private string _firstName; private string _lastName;
[DataMember] public string FirstName { get { return _firstName; } set { _firstName = value; } }
[DataMember] public string LastName { get { return _lastName; } set { _lastName = value; } }}
2. Use Data Members with Properties:
You can also use properties to control the serialization of private data. Define properties with both get
and set
accessors for serialization, and use private fields to store the actual data.
[DataContract]public class Person{ [DataMember] public string FirstName { get; set; }
[DataMember] public string LastName { get; set; }
// Private field not exposed directly but used internally private int Age { get; set; }}
3. Custom Serialization:
For more control, you can implement custom serialization logic by using IDataContractSurrogate
to customize how data is serialized and deserialized. However, this is more advanced and generally not required for standard use cases.
2.3 Serializing Methods
No, methods of a class do not get serialized in WCF Data Contracts. Serialization in WCF is concerned with the data that is being exchanged between the service and the client, not with the behavior or operations of the class.
1. What Gets Serialized
1. Data Members: Only public properties or fields that are decorated with the [DataMember]
attribute in a Data Contract are included in the serialization process. These are the data elements that are transferred between the client and the service.
2. Class Structure: The class structure, including its data members, is serialized into XML or JSON format (depending on the binding) so that it can be transmitted over the network. Methods, however, are not part of this process.
2. Example of a Data Contract
Here’s a simple example of a Data Contract:
[DataContract]public class Person{ [DataMember] public string FirstName { get; set; }
[DataMember] public string LastName { get; set; }
// This method will not be serialized public string GetFullName() { return $"{FirstName} {LastName}"; }}
- The
FirstName
andLastName
properties are data members and will be serialized. - The
GetFullName
method is a behavior of the class and will not be serialized. It is used for processing data but does not participate in the serialization process.
3. Why Methods Aren’t Serialized
1. Focus on Data: Serialization is focused on the data being exchanged, not on the operations or logic of the class. Including methods in serialization would complicate the data exchange model and is generally unnecessary for most communication scenarios.
2. Behavior vs. Data: Methods represent the behavior of the class, while serialization is concerned with transferring the state (data) of the class. The client and service typically communicate using data, and methods are used to process or manipulate that data on the client or server side.
4. Access Methods of a Serialized Object?
In WCF, when you serialize and send an object from a service to a client, only the data members of the object (i.e., the properties or fields marked with the [DataMember]
attribute) are transferred. Methods, which define behavior, are not serialized. Therefore, the client receives only the data, not the methods or behavior associated with the object.
To access methods and perform operations on the serialized data on the client side, you need to follow a different approach:
1. Define Service Contracts: Methods that clients need to call should be part of the WCF service contract. The service contract defines what operations (methods) are available to clients and how they can interact with the service.
[ServiceContract]public interface IMyService{ [OperationContract] Person GetPersonInfo(int id);}
In this example, GetPersonInfo
is a method exposed by the service, and it returns a Person
object.
2. Implement Service Methods: On the server side, implement the service contract and provide logic for the methods:
public class MyService : IMyService{ public Person GetPersonInfo(int id) { // Retrieve and return Person object return new Person { FirstName = "John", LastName = "Doe" }; }}
3. Client-Side Access:
On the client side, you interact with the service through a proxy that WCF generates based on the service contract. The client does not directly access methods of the Person
class but rather uses the service’s methods to get data and then operates on the data.
// Create a client proxy to communicate with the servicevar client = new MyServiceClient();
// Call the service methodPerson person = client.GetPersonInfo(123);
// Use the data received from the serviceConsole.WriteLine($"Name: {person.FirstName} {person.LastName}");
MyServiceClient
is a proxy class generated by WCF. Refer blow (next section) for more details.
4. Client Methods and Logic:
After receiving the data on the client side, you can implement your own logic or methods to work with the data. For example, you might have methods to process or display the Person
data:
public class PersonHandler{ public void DisplayPersonInfo(Person person) { Console.WriteLine($"Name: {person.FirstName} {person.LastName}"); }
public string GetFullName(Person person) { return $"{person.FirstName} {person.LastName}"; }}
In this example, PersonHandler
is a client-side class that provides additional functionality related to Person
objects.
4.1 Keypoints
- Service Contracts: Define the methods available for interaction between client and server.
- Service Implementation: Provides the actual logic for these methods on the server side.
- Client Proxy: Uses the service contract to call methods and receive data.
- Client-Side Logic: Implements additional functionality to work with the data received.
- By designing your WCF service and client interactions this way, you ensure that the client can access and use the methods and logic required to work with the data, even though the methods themselves are not serialized.
4.2 MyServiceClient
Proxy Class
MyServiceClient
is a proxy class generated by WCF that allows a client application to interact with a WCF service. It is not defined by you directly but is created by the WCF tooling based on the service contract defined on the server side.
How MyServiceClient
is Created
1. Service Reference:
When you add a service reference to your client application, Visual Studio (or another tool) generates a client proxy class, such as MyServiceClient
, based on the service contract (IMyService
) defined on the server.
-
In Visual Studio: You can add a service reference by right-clicking your project, selecting Add Service Reference, and providing the address of the WCF service. Visual Studio generates the proxy classes and configuration needed to communicate with the service.
-
In .NET Core/.NET 5+: You can use the
dotnet-svcutil
tool or theConnected Services
feature in Visual Studio to generate the client proxy.
2. Generated Proxy Class:
The generated MyServiceClient
class implements the service contract interface (IMyService
) and provides methods that correspond to the service operations. It handles the communication details between the client and the WCF service.
For example, if you have the following service contract:
[ServiceContract]public interface IMyService{ [OperationContract] Person GetPersonInfo(int id);}
The MyServiceClient
class will have a method GetPersonInfo
that you can call to interact with the service:
public class MyServiceClient : ClientBase<IMyService>, IMyService{ public Person GetPersonInfo(int id) { return Channel.GetPersonInfo(id); }}
This class is auto-generated and should be used to call service methods.
Using the Generated Client Proxy
Here’s how you typically use the generated MyServiceClient
class in your client application:
// Create an instance of the client proxyvar client = new MyServiceClient();
// Call the service methodPerson person = client.GetPersonInfo(123);
// Use the data received from the serviceConsole.WriteLine($"Name: {person.FirstName} {person.LastName}");
// Optionally, close the client when doneclient.Close();
Keypoints
MyServiceClient
is a proxy class generated by WCF tools based on the service contract.- It is automatically created when you add a service reference to your client application.
- You use this proxy class to call methods on the WCF service, which handles the communication details between the client and server.
- The client proxy provides a convenient way to interact with WCF services without having to deal with low-level communication details.