WCF Services

Services Contract :

Today, we'll talk about Service Contracts.

In every service oriented architecture, services share schemas and contracts, not classes and types (3rd SOA tenet). What this means is that you don't share class definitions neither any implementation details about your service to consumers. Everything your consumer has to know is your service interface, and how to talk to it. In order to know this, both parts (service and consumer) have to share something that is called a Contract. Contract must be seen as normalization for the service interface. Don't think in Contract as any kind of SLA, neither any details about the way your consumer calls your service (transport).

In WCF, we have 3 kinds of contracts: Service Contract, Data Contract and Message Contract. Today, I'll talk about the first one.

When you expose any service, lets say a Web Service for example, you're exposing a class, deriving WebService, which has some public methods that you decorate with WebMethod attribute. When you're doing this, indirectly, you're exposing a service contract. Like that, if you get the WSDL for your service, you'll see that you get an element with the name of your WebService (portType), and other elements with your web methods (operation), documenting what operations your service supports.

In WCF, the concept is the same. A Service Contract describes what the service can do for you. It defines some properties about the service, and a set of actions called Operation Contracts. Operation Contracts are equivalent to web methods in ASMX technology, or, if you prefer, to operation element in WSDL.

In WCF, contracts are interfaces (this is not completely true, since there is another way of indirectly declare service contracts, but you should assume it as a best practice), decorated with special attributes. Those special attributes are ServiceContract and OperationContract. As an example, lets assume you want a service named SumService in order to Sum two values. In WCF, you could define something like:

[ServiceContract()]
public interface ISumService
{
[OperationContract()]
double Sum(double val1, double val2);
}

When you're doing this, you're normalizing your service contract, and it's interface, by saying that you're exposing a Sum operation, which accepts two double arguments, and returns a double result.

This is very, very simple, right ? If you follow some Enterprise Integration Patterns, you're doing this right now. Or, if you're using Contract First Development, you're also doing this, even if you choose to schema first your contracts. The only thing special about WCF Service Contracts, are the decoration attributes. Those attribute are very important and they say to WCF how to expose your service to outside.

If you wanted to implement an instance of your service contract, it would be as simple as to write your service implementation class which implements ISumService. That service would look something like:

public class SumService : ISumService
{
public double Sum(double val1, double val2)
{
return val1 + val2;
}
}

Simple, no ? If you're new to Messaging and SOA, I'll recommend Messaging Pattern (53) from "Enterprise Integration Patterns" (0-321-20068-3)

Next post will talk about Data Contracts.

Calling WCF from JQuery File IService.cs
[ServiceContract] public interface IService1 { [OperationContract] [WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json)] string GetData(int value); [OperationContract] [WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json)] string GetRSS(); [OperationContract] [WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json)] string[] GetUser(string Id); // TODO: Add your service operations here } Service.cs public class Service1 : IService1 { public string GetData(int value) { return string.Format("You entered: {0}", value); } public string GetRSS() { //Create a WebRequest WebRequest rssReq = WebRequest.Create("http://www.asp.net/news/rss.ashx"); //Set the timeout in Seconds for the WebRequest rssReq.Timeout = 5000; try { //Get the WebResponse WebResponse rep = rssReq.GetResponse(); //Read the Response in a XMLTextReader XmlTextReader xtr = new XmlTextReader(rep.GetResponseStream()); //Create a new DataSet DataSet ds = new DataSet(); //Read the Response into the DataSet ds.ReadXml(xtr); string str = DataTableToJSONWithStringBuilder(ds.Tables[2]); return str; //Bind the Results to the Repeater //rssRepeater.DataSource = ds.Tables[2]; //rssRepeater.DataBind(); } catch (Exception ex) { throw ex; } } public string DataTableToJSONWithStringBuilder(DataTable table) { var JSONString = new StringBuilder(); if (table.Rows.Count > 0) { JSONString.Append("["); for (int i = 0; i < table.Rows.Count; i++) { JSONString.Append("{"); for (int j = 0; j < table.Columns.Count; j++) { if (j < table.Columns.Count - 1) { JSONString.Append("\"" + table.Columns[j].ColumnName.ToString() + "\":" + "\"" + table.Rows[i][j].ToString() + "\","); } else if (j == table.Columns.Count - 1) { JSONString.Append("\"" + table.Columns[j].ColumnName.ToString() + "\":" + "\"" + table.Rows[i][j].ToString() + "\""); } } if (i == table.Rows.Count - 1) { JSONString.Append("}"); } else { JSONString.Append("},"); } } JSONString.Append("]"); } return JSONString.ToString(); } public string[] GetUser(string Id) { return new User().GetUser(Convert.ToInt32(Id)); } } public class User { Dictionary users = null; public User() { users = new Dictionary(); users.Add(1, "pranay"); users.Add(2, "Krunal"); users.Add(3, "Aditya"); users.Add(4, "Samir"); } public string[] GetUser(int Id) { var user = from u in users where u.Key == Id select u.Value; return user.ToArray(); } } Jquery var Type; var Url; var Data; var ContentType; var DataType; var ProcessData; $(document).ready(function () { WCFJSON(); }); function WCFJSON() { var userid = "1"; Type = "POST"; Url = "http://localhost:49625/Service1.svc/GetUser"; Data = '{"Id": "' + userid + '"}'; ContentType = "application/json; charset=utf-8"; DataType = "json"; varProcessData = true; CallService(); } //function to call WCF Service function CallService() { $.ajax({ type: Type, //GET or POST or PUT or DELETE verb url: Url, // Location of the service data: Data, //Data sent to server contentType: ContentType, // content type sent to server dataType: DataType, //Expected data format from server processdata: ProcessData, //True or False success: function (msg) {//On Successfull service call ServiceSucceeded(msg); }, error: ServiceFailed// When Service call fails }); } function ServiceFailed(result) { alert('Service call failed: ' + result.status + '' + result.statusText); Type = null; varUrl = null; Data = null; ContentType = null; DataType = null; ProcessData = null; } function ServiceSucceeded(result) { if (DataType == "json") { resultObject = result.GetUserResult; for (i = 0; i < resultObject.length; i++) { alert(resultObject[i]); } } } function ServiceFailed(xhr) { alert(xhr.responseText); if (xhr.responseText) { var err = xhr.responseText; if (err) error(err); else error({ Message: "Unknown server error." }) } return; }