We will create a simple WCF service which will be hosted in a custom console application. A win form application is used as the WCF client.
WCF Service
We will start with a
ServiceContract interface which will be implemented by a
ServiceBehavior class.
[ServiceContract()]
public interface IUserService
{
[OperationContract]
void AddUser(UserDataContract user);
[OperationContract]
void RemoveUser(int userId);
[OperationContract]
List<UserDataContract> GetUsers();
[OperationContract]
string Echo(string msg);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class UserService : IUserService
{
List<UserDataContract> users = new List<UserDataContract>();
public void AddUser(UserDataContract user)
{
users.Add(user);
Console.WriteLine(string.Format("User {0} {1} added", user.FirstName, user.LastName));
}
public void RemoveUser(int userId)
{
for (int i = 0; i < users.Count; i++)
{
if (users[i].Id == userId)
{
Console.WriteLine(string.Format("User {0} {1} removed", users[i].FirstName, users[i].LastName));
users.Remove(users[i]);
return;
}
}
Console.WriteLine(string.Format("User {0} does not exist", userId));
}
public List<UserDataContract> GetUsers()
{
Console.WriteLine(string.Format("User list returned. {0} users", users.Count));
return users;
}
public string Echo(string msg)
{
Console.WriteLine("Invoked with " + msg);
return "Haaalo, " + msg;
}
}
Here the service InstanceContextMode is declared as InstanceContextMode.Single to have a singleton behavior.
Please click here for more details for InstanceContextMode in msdn.
Now a
DataContract can be created which is the agreement between service and client that abstractly describes the data to be exchanged.
[DataContract]
public class UserDataContract
{
int id;
string firstName;
string lastName;
[DataMember]
public int Id
{
get { return id; }
set { id = value; }
}
[DataMember]
public string FirstName
{
get { return firstName; }
set { firstName = value; }
}
[DataMember]
public string LastName
{
get { return lastName; }
set { lastName = value; }
}
}
WCF Service Host
A Service Host is needed to host the service just created. A simple console application is used as a host here. The below configuration specifies the end points exposed by the service. Different endpoint can be created for different binding.
<configuration>
<system.serviceModel>
<services>
<service name="UserServiceLibrary.UserService">
<endpoint address="http://localhost:8080/userservice/svc" binding="basicHttpBinding"
bindingConfiguration="" contract="UserServiceLibrary.IUserService" />
<endpoint address="net.tcp://localhost:8081/userservice/svc" binding="netTcpBinding"
bindingConfiguration="" contract="UserServiceLibrary.IUserService" />
</service>
</services>
</system.serviceModel>
</configuration>
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(
typeof(UserService), new Uri("http://localhost:8085/userservice")))
{
host.Open();
Console.WriteLine("{0} is open and has the following endpoints:\n",
host.Description.ServiceType);
int i = 1;
foreach (ServiceEndpoint end in host.Description.Endpoints)
{
Console.WriteLine("Endpoint #{0}", i++);
Console.WriteLine("Address: {0}", end.Address.Uri.AbsoluteUri);
Console.WriteLine("Binding: {0}", end.Binding.Name);
Console.WriteLine("Contract: {0}\n", end.Contract.Name);
}
Console.ReadLine();
}
}
}
WCF Win Client
An interactive win form application is used as the client. The below configuration defines the named endpoint configurations used by the ChannelFactory. These addresses should match with the addresses specified earlier with the host configuration.
<configuration>
<system.serviceModel>
<client>
<endpoint name="usHttpEndpoint"
address="http://localhost:8080/userservice/svc"
binding="basicHttpBinding"
contract="UserServiceLibrary.IUserService"/>
<endpoint name="usTcpEndpoint"
address="net.tcp://localhost:8081/userservice/svc"
binding="netTcpBinding"
contract="UserServiceLibrary.IUserService"/>
</client>
</system.serviceModel>
</configuration>
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnAdd_Click(object sender, EventArgs e)
{
try
{
using (ChannelFactory<IUserService> httpFactory = new ChannelFactory<IUserService>("usHttpEndpoint"))
{
IUserService svc = httpFactory.CreateChannel();
UserDataContract user = new UserDataContract();
user.Id = int.Parse(userId.Text);
user.FirstName = firstName.Text;
user.LastName = lastName.Text;
svc.AddUser(user);
}
}
catch (Exception ex)
{
output.Text = ex.Message;
}
}
private void btnDelete_Click(object sender, EventArgs e)
{
try
{
using (ChannelFactory<IUserService> httpFactory = new ChannelFactory<IUserService>("usHttpEndpoint"))
{
IUserService svc = httpFactory.CreateChannel();
svc.RemoveUser(int.Parse(userId.Text));
}
}
catch (Exception ex)
{
output.Text = ex.Message;
}
}
private void btnShowAll_Click(object sender, EventArgs e)
{
try
{
using (ChannelFactory<IUserService> httpFactory = new ChannelFactory<IUserService>("usHttpEndpoint"))
{
IUserService svc = httpFactory.CreateChannel();
List<UserDataContract> users = svc.GetUsers();
StringBuilder sb = new StringBuilder();
foreach (UserDataContract user in users)
{
sb.AppendFormat("{0} {1}/{2}\r\n", user.FirstName, user.LastName, user.Id);
}
output.Text = sb.ToString();
}
}
catch (Exception ex)
{
output.Text = ex.Message;
}
}
}
Below is a snapshot of the client form where in we can add, delete and list the users.
Now the service is ready to be tested. Start the host console application and once ready, start the client to communicate with the service.
Output
After adding 2 users and retrieving the list of users the output will look as below.