Creating WCF Service Library
i. Creating a new WCF Service Library and adding our service
The WCF Service Library template is present under WCF project type while creating a new project in Visual Studio.So, create a New Project ->navigate to WCF option -> select WCF Service Library and give some name. Here we are naming it as WCFJobsLibrary.
This will create a service library with a default service interface and a class to implement it. As we don’t need them, we simply delete them and create a service with our own custom name. For this, in Solution Explorer, right click on the project, select Add -> New Item and choose WCF Service. We name it as Jobs.
This step will create an IJobs interface and
Jobs
class.
Also, the service configuration for Jobs will be automatically written
in App.Config by Visual Studio. You can see this if you scroll down to
<services> tag for end point details and <behaviors>
tag for service behaviour under <system.serviceModel>
.By default, two endpoints will be created- one which uses
wsHttpBinding
and a mex endpoint with mexHttpBinding
. The mex endpoint provides metadata to the client for creating a proxy, the process which we’ll discuss later.ii. Preparing our own complex type and making it serializable & WCF-enabled
Right now, we’ll proceed to write the code for our service. In Jobs class we are going to define a method which returns a complex type with Job details. For this complex type we should prepare a class with all the required fields. So, add a new class from Add -> New Item and name it as Job.cs.The class must be specified by
[DataContract]
attribute to make it serializable and WCF-enabled. Similarly the properties should be specified with [DataMember]
attribute. As these attributes are present in System.Runtime.Serialization
namespace which is not available in the class by default, we need to import that namespace.using System.Runtime.Serialization;
namespace WCFJobsLibrary
{
[DataContract]
public class Job
{
[DataMember]
public string Description { get; set; }
[DataMember]
public int MinLevel{get;set;}
[DataMember]
public int MaxLevel { get; set; }
}
}
iii. Adding Contracts
Now, our next step is to add the contract. For this, in IJobs interface we specify our methods and decorate them with[OperationContract]
attribute. [ServiceContract]
public interface IJobs
{
[OperationContract]
DataSet GetJobs();
[OperationContract]
Job GetJobInfo(int Jobid);
}
Here the two methods perform nearly the same action, with a slight difference that GetJobs()
method will fetch all the records in the Jobs table, whereas GetJobInfo()
will fetch only the record matching the given Jobid.GetJobs()
returns a DataSet which is an in-built complex type, whereas GetJobInfo
will return Job type which we have already defined in our Job class.iv. Implementing the Interface
We implement theIJobs
interface in Jobs class. For this we go to Jobs class and right click on IJobs
and select Implement Interface option to implement IJobs interface automatically in Jobs class. When this is done, we get empty methods where we have to write our code. The code for the methods is written as follows:public class Jobs : IJobs
{
#region IJobs Members
public System.Data.DataSet GetJobs()
{
SqlConnection cn = new SqlConnection("data source=mytoy; user
id=sa; database=pubs");
DataSet ds = new DataSet();
SqlDataAdapter da = new SqlDataAdapter("Select * from jobs", cn);
da.Fill(ds, "jobs");
return ds;
}
public Job GetJobInfo(int Jobid)
{
SqlConnection cn = new SqlConnection("data source=mytoy; user id=sa;
database=pubs");
cn.Open();
string sqlstat = "select * from jobs where job_id=" + Jobid;
SqlCommand cmd = new SqlCommand(sqlstat, cn);
SqlDataReader dr=cmd.ExecuteReader();
Job jobObj=new Job();
if(dr.Read())
{
jobObj.Description=dr["job_desc"].ToString();
jobObj.MinLevel=Convert.ToInt32(dr["min_lvl"].ToString();
jobObj.MaxLevel=Convert.ToInt32(dr["max_lvl"].ToString();
}
else
jobObj.Description="-1";
return jobObj;
}
#endregion
}
There’s nothing much to discuss in this code, which performs the task
of retrieving required data from the database. For clarity, all the
connection strings and statements are hard-coded here, but you can do it
in a standard way. The main thing to note here is that these two
methods are getting data from database and returning it in complex
types.With this our service is ready. To pack it in an assembly we should build the project. After successfully building, we’ll get a dll in bin folder of project directory which is WCFJobsLibrary.dll.
Testing the WCF Service
After the library is built, run the assembly. This will host our service in the test environment. A new icon appears in task bar which shows that the service is hosted.
Also a test client window is opened which gives the status information that the service is successfully added.
The service client has the information of the address and binding that is used. It even has the info of the methods that are available for consumption. In test environment, some methods may not be supported, which is because some complex types are not supported by the test client. For whichever methods are not supported, an exclamation mark appears beside the name of that method as shown in above screenshot for
GetJobs()
.Nevertheless, we can test the other method
GetJobInfo()
.
Just click on that service method in test client window and it will
show the service info at the right side of the window. This info is
divided into Request and Response parts. In Request the parameter names,
their values and types are listed. Similarly in Response the info of
return types are given. When we enter a parameter value in Request and
press the invoke button, it will give the result in Response as shown in
screenshot below.But if the test client window is closed, the service is also removed from the host environment. To make the service independent of this test client, we have to detach the test client from the project. To do this go to
WCFJobsLibrary
properties and move to the Debug tab. Here we’ll find the test client
name in command line arguments box. Removing the client name from that
box will detach the client from the service. Consuming the WCF Service
As we have successfully tested the service, our next step is to consume it. For this we create a windows app as our client.i. Design the Form
Create New > Project > Windows Forms App and name it as ConsumeJobs.We design the form as shown below with a textbox to provide the
JobId
,
a button to invoke the sevice and a few more textboxes to display the
results. Similarly we use a DataGridView and another button to display
all the records in Jobs table.ii. Creating Proxy
To communicate with the service, the client should have a proxy.For creating a proxy the client needs the reference of WCF service.
For adding reference go to Solution Explorer and right click the project (client app) and choose Add Service Reference. A window opens where we have to give the address of the service. We can copy this address from the base address in app.config file of our WCF Service Library. If the communication between the client and server is through http, then we can use that address as it is, otherwise if it is through any other channel, then we need to add ‘/mex’ at the end of the address.
For example if the base address is :
http://localhost:8731/Design_Time_Addresses/WCFJobsLibrary/Jobs/
then for any channels other than http we have to add ‘/mex’ at the end like this:
http://localhost:8731/Design_Time_Addresses/WCFJobsLibrary/Jobs/mex
After providing the address and clicking the Go button, the services available at that address are found and also a list of interfaces at that services are shown. It should be remembered that this step will be successful only if the service is running.
Select the service and provide a meaningful name for the namespace(alternately you can use the default name as well). In our case we provide the name as JobsService. When the ok button is clicked, a proxy will be created at the client with a similar name as the original class at the service, but suffixed by the word ‘client’. In the WCF Service library as our class name is Jobs, at the client side the proxy name will be JobsClient.
iii. Writing Code to Consume Service
As the proxy class is created we can proceed to write the code in button click events of the client Windows form.private void btnViewDetails_Click(object sender, EventArgs e)
{
//an instance of the proxy class
JobsService.JobsClient obj = new ConsumeJobs.JobsService.JobsClient();
//Reading the result into complex type object (Job type)
JobsService.Job jobObj = obj.GetJobInfo(int.Parse(txtJobId.Text));
//Displaying result in text boxes
txtDescription.Text = jobObj.Description;
txtMinValue.Text = jobObj.MinLevel.ToString();
txtMaxValue.Text = jobObj.MaxLevel.ToString();
}
private void btnShow_Click(object sender, EventArgs e)
{
JobsService.JobsClient obj = new ConsumeJobs.JobsService.JobsClient();
DataSet ds = obj.GetJobs();
dataGridView1.DataSource = ds.Tables[0];
}
We get the result from the database which is retrieved by the service program and which is in turn accessed by a proxy class at the client.Till now we have seen about consuming the service when it is hosted in the hosting environment provided by Visual Studio. Now we’ll see how to register this service with Windows so that it runs as a Windows service.
Creating Windows Service for Hosting the Service DLL
For this, first we have to create a Windows service. This can be done from Visual Studio using the Windows Service template which can be found under Windows project type.New > Project > Windows Service > name it as ABCService
We have to add the reference of our WCF DLL in this service. To do this, right click on the project in Solution Explorer and select Add Reference. For adding the dll in reference, select browse tab in the window that appears, and navigate to the folder where our WCF service library is located. In that location, the dll can be found inside the bin-> debug folder. When this dll is added, it is imported into the Windows service app.
Similarly we need reference of
System.ServiceModel
namespace because it is not available by default in Windows Service. To go to the code window of the service class,
go to the design view of the service that is created by default and
click on the link ‘click here to switch to code view’. This link will
take you to the code view. Import the System.ServiceModel
namespace here as it is required for hosting our WCF service. The default service class Service1.cs
provides two events – OnStart and OnStop. We can write our code as what
we want to do when our service starts and stops in these two events
respectively.The code for this class is written as shown below:
namespace ABCService
{
public partial class Service1 : ServiceBase
{
ServiceHost sHost;
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
sHost = new ServiceHost(typeof(WCFJobsLibrary.Jobs));
sHost.Open();
}
protected override void OnStop()
{
sHost.Close();
}
}
}
We are just creating a service host for our WCF library
in the OnStart event and opening it. When the Windows service is
closed, it should close the service host, which is specified in the
OnStop event. Merely writing this code will not suffice as we need to have the configurations also. We need to do the configurations in order that the service be hosted and run properly as needed. These configurations are to be specified in App.Config file in the Windows Service app. As this file is not available by default, we have to create it by adding it as a new item and selecting the Application Configuration File template.
The created App.Config file has empty configurations i.e. no configurations are specified under <configuration> tag. Instead of tediously writing all these configurations we can just copy them from the App.Config of our service library. Copy everything available under <system.serviceModel> and paste it in App.Config of the windows service.
Now build the service. This will complete our steps of hosting our WCF service as a Windows service. Now only thing remaining is to register it with Windows OS.
Registering the Service with Windows OS
- Go to the design view of the Windows service, right click and click on Add Installer option.
- When this is clicked, we get two processes –
ServiceProcessInstaller
andServiceInstaller
. Click onServiceProcessInstaller
and set its account property to local system.
Now, click onServiceInstaller
and provide some display name, say,ABCNITJobsService
. Also choose the start type- manual or automatic or Disabled. In our case we can either choose manual or automatic.
- Now build the service once again. This will create an executable
file called ABCService(in our case) which can be located in the project
directory.
This exe file should be registered with Windows OS to make it run as a service.
- Copy the path of this exe file location and open the containing folder from command prompt.
In that path write the command InstallUtil ABCService.exe which registers the service with Windows OS.
Once it is registered with Windows, we can see it in the services list.
(Control Panel > Administrative Tools > Services)
If it is not automatically started, we can start it manually by clicking the start link.
- When the service is started, we can find whether it is listening or not by using the netstat –a command in the command prompt.
Note: If Vista OS is used, then it should be run in Administrator mode for hosting the service.
No comments:
Post a Comment