Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

Simple WCF Hosting and Consuming

3.83/5 (5 votes)
22 Sep 2008CPOL4 min read 1   977  
Simple WCF Hosting and Consuming

Introduction

In this article, we will discuss about Windows Communication Foundation (WCF) hosting options and how we can consume the WCF services. One of the hosting methods of WCF Service is just like the traditional ASMX Web services hosted can be done with Microsoft Internet Information Services (IIS). The other hosting options for WCF services are significantly enhanced in Microsoft .NET Framework 3.0. We will not discuss extending the hosting model to include Windows Services and Self-Hosting options. We will only explore the IIS hosting options available for WCF services in a simple way.

Background

Recently, I tried to find a simple WCF example to have both how the service is created and also how it is being consumed. However, most of the examples I got are either outdated or they are too complex to understand. Therefore I decided to create one on my own. The example below uses the default template from Visual Studio 2008.

The 'ABC' in WCF

This is now becoming a popular way to understand how WCF works. A is the address, B the binding and C the contract.

Address is where you communicate. This is not the same as the location you deploy your service, but the URL that will be used internally to map your requests and responses.

Binding is how you communicate. There are several default ones like BasicHttp, TCP, NamedPipes, MSMQ and several others. This is the protocol that the server and client understand while communicating.

Contract is what you communicate. Refer to the next section for details on contracts.

Create a WCF Service

First create a new Visual Studio 2008 project and Select WCF Service Application as your new project.

main.JPG

Create a Service Contract

In WCF, all services are exposed as contracts. Contract is a neutral way of describing what the service does. Mainly we have four types of contracts discussed below.

Service Contract

This contract describes all the available operations that the client can perform on the service. .NET uses System.ServiceModel namespace to work with WCF services. ServiceContract attribute is used to define the service contract. We can apply this attribute on class or interface. Servicecontract attribute exposes a CLR interface (or a class) as a WCF contract. OperationContract attribute is used to indicate explicitly which method is used to expose as part of the WCF contract. We can apply OperationContract attribute only on methods, not on properties or indexers. [ServiceContract] applies at the class or interface level. [OperationContract] applies at the method level.

C#
[ServiceContract]
public interface IService1 
{
[OperationContract]
Response GetMessage(Request request);

[OperationContract]
string SayHello();

[OperationContract]
string WelcomeHello(string Name);

[OperationContract]
string ViewHello(Request request);

[OperationContract]
int AddService(AddCalculator Number);
}

Data Contract

This contract defines the data types that are passed in and out of the service. [DataContract] attribute is used at the custom data type definition level, i.e. at class or structure level. [DataMember] attribute is used for fields, properties, and events.

C#
// Use a data contract as illustrated in the sample below to add composite
// types to service operations.
[DataContract(Namespace = 
	"http://schemas.datacontract.FirstWCF.org/ServiceHost/2008/09")]
public class Request
{
string name;

[DataMember]
public string Name
{
get { return name; }
set { name = value; }
}
}

[DataContract(Namespace = 
	"http://schemas.datacontract.FirstWCF.org/ServiceHost/2008/09")]
public class Response
{
string message;

[DataMember]
public string Message
{
get { return message; }
set { message = value; }
}
}

[DataContract(Namespace = 
	"http://schemas.datacontract.FirstWCF.org/ServiceHost/2008/09")]
public class AddCalculator
{
int x, y;

[DataMember]
public int First_Integer
{
get { return x; }
set { x = value; }
}

[DataMember]
public int Second_Integer
{
get { return y; }
set { y = value; }
}
}

Fault Contract

This contract describes the error raised by the services. [FaultContract(<<type of Exception/Fault>>)] attribute is used for defining the fault contracts.

Message Contracts

This contract provides direct control over the SOAP message structure. This is useful in inter operability cases and when there is an existing message format you have to comply with. [MessageContract] attribute is used to define a type as a Message type. [MessageHeader] attribute is used for those members of the type we want to make into SOAP headers. [MessageBodyMember] attribute is used for those members we want to make into parts of the SOAP body of the message.

There are several situations where you want to use this, but this is out of context for this guideline. Both of these contracts can be in the same file or in different files. In our case, we put it into IService1.cs.

Build Logic/ Content of the Service

You can build your Service login into a new C# file that you can create in the C# background file of Service1.svc whose name is Service1.svc.cs.

The content of Service1.svc is as follows:

C#
<%@ServiceHost Language="C#" Service="CalculatorService.Service1"
    CodeBehind="Service1.svc.cs" %>

You can change the service logic to a DLL service logic by adding the DLL file as a reference and the content of the Service1.svc will look like this:

XML
<%@ServiceHost Language="C#" Service="SampleService.Service" %>

The content of Service1.svc.cs is where the logic of the Service is set. We can also call this as an [OperationBehavior].

C#
namespace CalculatorService
{
// NOTE: If you change the class name "Service1" here, you must also update the
// reference to "Service1" in Web.config and in the associated .svc file.
public class Service1 : IService1
{
[OperationBehavior]
public Response GetMessage(Request request)
{
//a response object to return
Response response = new Response();
//check if the request is null, then send error.
if (request == null)
{
response.Message = "Error!";
}
else
{
//set the message
response.Message = "Hello," + request.Name;
}
return response;
}

[OperationBehavior]
// Function that returns a string
public string SayHello()
{
return "Welcome to First WCF Service! \n\nPlease Enter Your Name";
}

[OperationBehavior]
// Function that returns a string by passing one value in
public string WelcomeHello(string Name)
{
return "Hello, " + Name;
}

[OperationBehavior]
// Function that returns an object by passing one value in
public string ViewHello(Request request)
{
//a response object to return
Response response = new Response();
//check if the request is null, then send error.
if (request.Name == null)
{
response.Message = "No Message";
}
if (request == null || request.Name == "")
{
response.Message = response.Message + "Error!";
}
else
{
//set the message
response.Message = response.Message + "Hello, " + request.Name;
}

return response.Message;
}

[OperationBehavior]
// Function that returns a string by passing one value in
public int AddService(AddCalculator Number)
{
return Number.First_Integer + Number.Second_Integer;
}
}
}

Test the Service

You will get the page below when you run the service:

done.JPG

Create a WCF Window Console Client

Create a new Windows project and select Console application as your new project. After creation of the new project, right click on the project and click on the Add Service Reference:

addservice.JPG

After the Service is added, your app.config file will be created and you will get a new folder in your solution explorer named "Service References":

addservice2.JPG

Edit your app.config file. Change all the binding from wsHttpBinding to BasicHttpBinding.

Create A Service Proxy

Service proxy is used to communicate with the service.

C#
using System;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Runtime.Serialization;

namespace CalculatorService
{
[ServiceContract]
public partial interface IService1
{
[OperationContract]
Response GetMessage(Request request);

[OperationContract]
string ViewHello(Request request);

[OperationContract]
string SayHello();

[OperationContract]
string WelcomeHello(string Name);

[OperationContract]
int AddService(AddCalculator Number);
}

[DataContractAttribute(Namespace =
    http://schemas.datacontract.FirstWCF.org/ServiceHost/2008/09)] 
    [SerializableAttribute()]
public class Request
{
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string name;

[DataMemberAttribute]
// Data Member Name must be same as the Data Contract In the Service
public string Name
{
get { return name; }
set { name = value; }
}
}

[DataContractAttribute(Namespace =
    "http://schemas.datacontract.FirstWCF.org/ServiceHost/2008/09")]
[SerializableAttribute()]
public class Response
{
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string message;

[DataMemberAttribute]
// Data Member Name must be same as the Data Contract In the Service
public string Message
{
get { return message; }
set { message = value; }
}
}

[DataContractAttribute(Namespace =
    "http://schemas.datacontract.FirstWCF.org/ServiceHost/2008/09")]
[SerializableAttribute()]
public class AddCalculator
{
[System.Runtime.Serialization.OptionalFieldAttribute()]
private int x,y = 0;

[DataMemberAttribute]
// Data Member Name must be same as the Data Contract In the Service
public int First_Integer
{
get { return x; }
set { x = value; }
}

[DataMemberAttribute]
// Data Member Name must be same as the Data Contract In the Service
public int Second_Integer
{
get { return y; }
set { y = value; }
}
}

public partial class SampleServiceClient : ClientBase<iservice1 />, IService1
{
public SampleServiceClient()
{ }
public SampleServiceClient(string endpointConfigurationName) : base(
    endpointConfigurationName)
{ }
public SampleServiceClient(string endpointConfigurationName,
    string remoteAddress) : base(endpointConfigurationName, remoteAddress)
{ }
public SampleServiceClient(string endpointConfigurationName,
    System.ServiceModel.EndpointAddress remoteAddress) : 
    base(endpointConfigurationName,
    remoteAddress)
{ }

public Response GetMessage(Request request)
{
return Channel.GetMessage(request);
}

public string SayHello()
{
return Channel.SayHello();
}

public string WelcomeHello(string name)
{
return Channel.WelcomeHello(name);
}

public string ViewHello(Request request)
{
return Channel.ViewHello(request);
}

public int AddService(AddCalculator Number)
{
return Channel.AddService(Number);
}
}
}

Code on the Client Main Program

C#
namespace WindowServiceClient
{
class Program
{
static void Main(string[] args)
{
Request request = new Request();
SampleServiceClient service = new SampleServiceClient("BasicHttpBinding_IService1");
// Initiate Welcome Screen
Console.WriteLine(service.SayHello());
Console.WriteLine("\nPlease Enter Your Name \n");
// Say Hello to user entry - Test Return String via string input
string name = Console.ReadLine();
Console.WriteLine(service.WelcomeHello(name));

Console.WriteLine("\nPlease Enter a message \n");
// Say Hello to user entry - Test Return string via string input to object
request.Name = Console.ReadLine();
Console.WriteLine(service.ViewHello(request));

// Say Hello to user entry - Test Return object with string as member via string
// input to object
Console.WriteLine(service.GetMessage(request).Message);
// Call calculator function - Test input with logic and return new result.
AddCalculator number = new AddCalculator();
Console.WriteLine("\nPlease Enter First Number \n");
number.First_Integer = Convert.ToInt32(Console.ReadLine().ToString());

Console.WriteLine("\nPlease Enter Second Number \n");
number.Second_Integer = Convert.ToInt32(Console.ReadLine().ToString());

Console.WriteLine("The Sum of " + number.First_Integer + " + " +
    number.Second_Integer + " = " + service.AddService(number));
Console.ReadKey();
}
}
}

Sample Output

result.JPG

result2.JPG

History

  • 22nd September, 2008: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)