Thursday, November 15. 2007Windows Communication Foundation WCF Notes
These are my notes for Windows Communication Foundation. It covers many aspects of WCF services, and it can easily be used as a quick WCF tutorial.
ContractA C# interface acts as a service contract for a WCF service. The interface needs to have ServiceContract attribute, and all functions needs to have OperationContract attribute.
[ServiceContract]
public interface IAdder
{
[OperationContract]
int Add (int a, int b);
}
OperationContract can have a set of parameters such as IsInitiating, IsTerminating, IsOneWay, etc.
Operations that may throw exceptions should also have a set of FaultContract's for each exception type that they may throw. For example, if our Add operation may thow an ArgumentException, then the operation should be marked as:
[OperationContract] [FaultContract(typeof(ArgumentException))] int Add (int a, int b);
Operations mostly takes and returns standard data types, such as int, string, etc. Other data types can also be introduced using the DataContract, and all fields that you would like to serialize needs to have DataMember attribute.
[DataContract]
public class Person
{
[DataMember]
string firstName;
[DataMember]
string lastName;
}
This approach is only applicable if you hold the source code to the data type. For all other data types that is known at both service and client, you can use the ServiceKnownType attribute.
[ServiceContract]
[ServiceKnownType(typeof(AssemblyVersionCompatibility))]
public interface IService
{
}
Creating the ServiceCreate a new class and simply implement the contract interface.
class AdderService : IAdder
{
int Add (int a, int b)
{
if (a == 0 || b == 0)
throw new ArgumentException("Don't waste the bandwith!");
return a + b;
}
}
Hosting the ServiceIn order to host the service, use the ServiceHost.
// We will use TCP binding
NetTcpBinding netTcpBinding = new NetTcpBinding();
// Address of our service
Uri serviceUri = new Uri("http://localhost:9090/AddserService");
// Host our service
ServiceHost serviceHost = new ServiceHost(typeof(AdderService), serviceUri);
serviceHost.AddServiceEndpoint(typeof(IWorker), netTcpBinding, string.Empty);
serviceHost.Open();
You can use other bindings, such as HTTP binding, as well. In the example, we are configuring the hosting programatically, but you can also use the WCF Configuration application to configure hosting through a GUI. WCF stores the configuration information inside the application configuration file, App.config. Connecting to the ServiceWCF provides helper applications to create the proxy classes on the client side automatically from the metadata. In addition to that, assuming that you have the App.config file available, you can also use the WCF configuration application to create the proxy classes automatically. Assuming that you have the contract interface available in both service and client, you can also create the proxy programatically:
// We will use TCP binding
NetTcpBinding netTcpBinding = new NetTcpBinding();
// Address of our service
Uri serviceUri = new Uri("http://localhost:9090/AdderService");
// Create our channel factory
ChannelFactory adderFactory = new ChannelFactory(
netTcpBinding, new EndpointAddress(serviceUri));
// Create our transparent proxy
IAdder adder = adderFactory.CreateChannel();
// We can now use the service
int result = adder.Add(6, 8);
// We can now close the communication
((IChannel) adder).Close();
SessionsEach time we call an operation, WCF creates a new instance of our service. This behaviour can easily be changed adding an attribute to our service class.
[ServiceBehavior(InstanceContext = InstanceContext.PerSession)]
class AdderService : IAdder
{
}
InstanceContext can be the following:
MessagesIn normal cases you shouldn't have to touch the messages. But in some cases it becomes necessary. For example, assuming that your service will provide a File Upload operation. Here is the possible contract interface: [OperationContract] void Upload (string fileName, Stream stream); Unfortunetly, when using Streams, our operation can not take other parameters. So we cannot tell the fileName to our operation when uploading a file. You may always create two operations, one for setting the fileName, and the other one for uploading the file, but this is not a good solution. In order to solve this problem we will need to create a new message.
[MessageContract]
public class FileMessage
{
[MessageHeader]
public string fileName;
[MessageBody]
public Stream stream;
}
Our message class needs to have the MessageContract attribute. Since WCF only allows the Stream in message body, we are keeping the fileName in message headers. To keep a data in message header we are using the MessageHeader attribute, and to keep a data in message body we are using the MessageBody attribute. [OperationContract] void Upload (FileMessage message); This is the modified version of our contract. CallbacksWCF supports duplex communication between service and client also. In other words, service can also call a client's function to inform the client during an event. A callback contract must be defined, and client should implement that contract interface.
public interface IResult
{
[OperationContract]
void Result (int result);
}
Client needs to inform the WCF that it supports the callback. This is done when creating the ChannelFactory.
class Client : IResult
{
public void Result (int result)
{
Console.WriteLine("Result = {0}", result);
}
public Client ()
{
NetTcpBinding netTcpBinding = new NetTcpBinding();
Uri serviceUri = new Uri("http://localhost:9090/AdderService");
IChannelFactory channelFactory = new DuplexChannelFactory(
this, netTcpBinding);
IAdder adder = channelFactory.CreateChannel(serviceUri);
}
}
On the service side, the service gets the callback channel using the OperationContext's GetCallbackChannel method. IResult resultCallback = OperationContext.Current.GetCallbackChannel(); resultCallback.Result(5); Discovering Web Services During Rum-TimeAs you can see, in order to use a web service you need to know its address. You can store those address information anywhere but you still have to maintain that list, which may become a very time consuming task if you are dealing with a complex distributed application, like a big Grid. WS-Discovery protocol helps you to locate web services dynamically during run-time. It uses UDP multicast protocol to publish and find web services. Using this approach, you don't have to know the address of a web service in order to use it. You can discover them during rum-time, so you don't have to maintain a list of addresses. If you would like to learn more about WS-Discovery, please take a look at my article WS-Discovery to Find Web Services During Run-Time. If you found this post helpful, please "Kick" it so others can find it too: |
Calendar
CategoriesQuicksearch |
|||||||||||||||||||||||||||||||||||||||||||||||||


WS-Discovery is a WCF based multicast protocol to enable run-time discovery of services within ad-hoc networks. It allows you to discover the address of Web Services during run-time. WS-Discovery is a WCF based multicast protocol to enable run-time dis
Tracked: Nov 29, 17:41