Wednesday 13 March 2013

WCF: Duplex Contracts

WCF supports three types of message exchange patterns:

1. Request-Reply
This is the default mode. A point to note is that even if the return type of a service operation is “void” a response would still be sent back to the client.

2. One-way
In one-way operations, the service after queuing up the call doesn’t send anything back to the client. Few details:
- we need to apply “IsOneWay=true” on the operation we want to behave like a one-way
- method type return must be void
- for any exceptions in the service operation, client doesn’t receive any feedback (faults are not returned back).
- the client after making the call returns back immediately to continue execution even if the service operation is still in progress.

3. Duplex
Duplex allows two-way communication. The client makes a call to the service, and then later the service can make a separate call to the client (this call is different from the reply sent back to client for the first call). The call the service makes to the client has its own request-response flow. In Duplex communication, we need to have two contracts, one implemented by the service (incoming contract) and one by the client (callback contract).

Classic examples of duplex communication are chat applications, stock quote or game score notifications. Let’s try a stock quotes notification service.

Not all channels support duplex communication. The supported ones are: NetTcpBinding, NetNamedPipeBinding. and on HTTP we need to use the special wsDualHttpBinding (the standard http bindings - basicHttpBinding and wsHttpBinding are not bi-directional)

Demo - Stock Quote Service Application: Assume we are a service provider of stock quotes. We want to expose a service which would allow clients first to register with a stock symbol to receive stock quotes, and as long as client doesn’t disconnect or explicitly unregisters we will keep sending back messages with stock quotes.

Contracts:

We need two contracts in duplex:
- IRequestStockQuotes: incoming contract implemented at the service end
- IQuoteNotification: callback contract implemented by the client

namespace StockQuotes.Common
{
[ServiceContract(CallbackContract=typeof(IQuoteNotification))]
public interface IRequestStockQuotes
{
[OperationContract]
void RequestNotifications(string symbol);
}

[ServiceContract]
public interface IQuoteNotification
{
[OperationContract]
void SendQuote(StockQuote quote);
}
}

Service :

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class StockService : IRequestStockQuotes
{
public void RequestNotifications(string symbol)
{
Console.WriteLine("Got request for symbol:" + symbol);
IQuoteNotification client = OperationContext.Current.GetCallbackChannel<IQuoteNotification>();
StockQuote quote = QuoteEngine.GetQuote(symbol); //from a real-time quote server
client.SendQuote(quote);
}
}

The concurrency mode of the service needs to be ConcurrencyMode.Multiple or Reentrant, the default mode ConcurrencyMode.Single would create a deadlock situation. An alternative could be mark the callback operations “One-Way”.. In the service method we fetch the client callback from the OperationContext.Current.GetCallbackChannel<T> and call the method “SendQuote” to call the client.

Service Host:

ServiceHost host = null;
try
{
host = new ServiceHost(typeof(StockQuotesService.StockService));
host.Open();
foreach (ServiceEndpoint ep in host.Description.Endpoints)
{
Console.WriteLine(ep.Address.Uri.ToString());
}
Console.WriteLine("Stock service now running. \n<ENTER> to close.");
Console.ReadLine();
host.Close();
}
catch (CommunicationException)
{
if (host != null)
{
host.Abort();
}
}
catch (TimeoutException)
{
if (host != null)
{
host.Abort();
}
}
catch (Exception)
{
if (host != null)
{
host.Abort();
}
}

Client:

First we implement the callback contract -

namespace Client
{
public class QuoteNotification : IRequestStockQuotesCallback
{
public void SendQuote(StockQuote quote)
{
Console.WriteLine("Received quote (callback) from service: Symbol {0}, Quote {1}", quote.Symbol, quote.Quote);
}
}
}

An important point to note here is that , I used ‘Add Service Reference’ from Visual Studio and that’s why the name of callback contract was changed from IQuoteNotification to IRequestStockQuotesCallback. I think this was done by the code-generation utility to match the service interface name “IRequestStockQuotes”.

The calls:

static void Main(string[] args)
{
InstanceContext ctx = new InstanceContext(new QuoteNotification());
RequestStockQuotesClient client = null;

try
{
client = new RequestStockQuotesClient(ctx);
client.Open();
Console.WriteLine("ENTER to call service:");
Console.ReadLine();
client.RequestNotifications("MSFT");
client.RequestNotifications("INTL");
client.RequestNotifications("RIM");
client.RequestNotifications("NSDQ");
client.RequestNotifications("A");
Console.ReadLine();
client.Close();
}
catch (CommunicationException)
{
if (client != null)
{
client.Abort();
}
}
catch (TimeoutException)
{
if (client != null)
{
client.Abort();
}
}
catch (Exception)
{
if (client != null)
{
client.Abort();
}
}
}

Output:

Service console:


image
Client console:

image 
Further improvements:

What we did was our first implementation, there is a scope of improvement here. Right now the client calls the “RequestNotifications” service method and immediately the service sends back the quote. To get the next quote the client will again have to call the service, which is not a good implementation. Ideally the client should register to receive the quote stream and then whenever service gets a new quote it should send it to the client. This would create the live-streaming environment. We will try to accomplish that in next post.

Saturday 9 March 2013

Introducing OData

Last weekend I introduced myself to OData. Here are the findings :-)

Contents:

1. Scenarios
2. Approaches
3. OData
4. Using LINQPad to access NetFlix
5. Examples from the Real World (ecosystem)
6. Resources
7. Developing OData Services(WCF Data Service, ASP.NET Web API)
8. Accessing OData Services (.NET client, jQuery)
9. Limitations
10. And GData?

First let’s start with the scenarios or the domain where OData can be relevant.

Scenarios:

- Let’s say you are a company which runs buses. You are looking for ways to share the information about buses such as arrival time, frequency, operating hours, capacity, service closures etc. You want other web sites and smart phone applications to be able to access this data. How would you do it?
- Say you are working for an online video streaming company like NetFlix and you want to expose your data about movie titles, availability, reviews etc. You want to share this information over the web so that e-commerce web sites like Amazon can create a catalog of your products or you are writing a Windows 8 app to display data from NetFlix.
- Say you are manager of a government department and you have a legal requirement to expose the data about projects such as date of completion, cost, overruns, tenders etc. on a web site and also in a format which can be easily accessed by other govt. applications

Now for all these scenarios we could have created a web site and displayed data on it, thereby creating a data island. But how can we make the data “reusable”, so that other applications (web /mobile) could consume it?

Also, a common requirement among the use cases above is that they return a list of entries or items. It is not about a request-response where you build a request package with some parameters and the service sends back the response after doing some calculation. This is more about - I want to expose data on my company’s URL say www.example.com/movies to share all the movie titles or www.busservice.com/buses to expose information about all the buses I have and step deeper www.nybusservice.com/buses(11)/frequency to get the frequency of bus with ID of “11”.

Approaches:

1) SOAP: We could create a WCF service (which uses SOAP format), host it in IIS so that it could become part of the organization’s web infrastructure. Now SOAP enables us to use WS-* protocols, metadata (WSDL); we can define operations like GetMoviesTitles, GetMovieReviews and also give us security, transactions, reliability, interoperability over HTTP. It supports request-response pattern over HTTP Post. But that is a lot of stuff made available to us, which may not be useful to use in certain scenarios.

2) POX (Plain Old XML): We could expose a ASP.NET URL and return XML data (could be done by writing our own http handler). The problem here is the data structure. The clients will have to ‘know’ the schema before hand to access the data and also we need to write extra stuff to enable CRUD operations. The advantage here is we avoid all the SOAP overhead.

3) REST: REST is an architectural style using the concept of ‘resources’ and how we can identify them with a URI, along with a fixed verbs for actions – GET, POST, PUT and DELETE for the CRUD operations on those resources. By using these HTTP verbs, it is easy for consumers to realize what actions need to be performed for interacting with the data.

In the scenarios above, let’s add one more - assume you run a blogging engine like Blogger, WordPress etc. The posts that your users write on your blogging engine needs to be exposed in a way so that blog readers (like Google Reader) could read the posts. You could again send back XML containing a list of all the posts in your own XML format. But then what would happen if every blog engine out there created its own format. Of course as we know this problem has been solved – all the blog engines use a standard format called Atom or RSS. This makes it easier for feed readers to just point to a URL and get all the posts and because they know it’s in Atom format it makes it quite easy for them. The Atom format is only for getting resources, and AtomPub (used by OData) is for editing web resources.

If we come to think of it, wouldn’t it better if we could return an Atom/RSS feed from our services? The atom/rss feed XML is understood by modern day browsers so anyone with a browser could go to the URL and get the data. This is in fact possible today with WCF. We could create RESTful services and reply back syndication feeds in RSS or ATOM format, sending back a list of your business objects.

But there is still a need of some more functionality to make it useful. Functionality like metadata, paging and filtering the feeds, for this we use OData. So we can say “OData is exposing your business objects (as a list/collection) over HTTP URL in a RESTful manner, by returning data in XML-AtomPub format along with providing facilities like metadata, filtering and paging.”

OData:

The “O” in OData stands for “Open”, the full name is “Open Data Protocol”. It is REST based, using HTTP + AtomPub + JSON.

The definition from OData.org:
"The Open Data Protocol (OData) is a Web protocol for querying and updating data that provides a way to unlock your data and free it from silos that exist in applications today. OData does this by applying and building upon Web technologies such as HTTP, Atom Publishing Protocol (AtomPub) and JSON to provide access to information from a variety of applications, services, and stores."

Let’s explore the NetFlix OData a little. If we browse to the URL http://odata.netflix.com/v2/Catalog/, this is what we get:

image

Under the <service> we have various collections: Genres, Titles, TitleAwards so on. If want to get all the titles we browse to: http://odata.netflix.com/v2/Catalog/Titles, and we get

image


We can see here it starts with the tag <feed> and there is an <entry> tag for every Title returned by the NetFlix service. In the <entry> you will find an “id” which will point to the URL we can use to get details about that particular Title.

image 
If we go to URL http://odata.netflix.com/v2/Catalog/Titles('13aly') we get:

image

Using LINQPad to access OData services:

In the previous section we saw how we can see the OData in browser, now we will see how we can use LINQPad to access it.

I am using LINQPad 4, but the steps should be same for other versions. The first step is to ‘Add connection’ in LINQPad, for this you can click the ‘Add Connection’ link given in the left pane.

image 
Upon clicking we get this dialog:

image 
Select “WCF Data Services 5.1..” and click Next and enter the URI.

image 
After clicking OK, you should get the NetFlix in the connection list along with various collections it exposes.

image 
We can now query the data with LINQ queries. 

> Get 10 genres:
Genres.Take(10)

image 
> Get the movies released this year: 

image 
Examples (Live):

- http://pluralsight.com/odata/ (PluralSight is my favorite web site, here it gives data about courses, authors, modules etc.)
- http://data.stackexchange.com/stackoverflow/atom (the stackoverflow web site gives a good amount of data for questions, answers, comments etc.)
- http://odata.netflix.com/v2/Catalog/
- and more here: http://www.odata.org/ecosystem. This link gives the list of many companies which are offering OData as of today.

Resources:

- OData.org: Introduction
- MSDN: WCF Data Services
- MSDN: Open Data Protocol by Example
- OData with Scott Hanselman
- MSDN: Getting Started With OData Part 1: Building an OData Service
- MSDN: Getting Started With OData Part 2: Building an OData Services from Any Data Source
- OData: There’s is a feed for that

(The rest of sections will be coming in the next blog post)

Wednesday 6 March 2013

SQL Server 2012: IIF

SQL Server 2012 introduces the “IIF” function, it’s a shorthand for the CASE expression. I am sure C# developers would love it!

An example: here we are fetching the columns in the table (HumanResources.Employee) using sys.columns and sys.types

> Using CASE

USE
AdventureWorks2012
GO

SELECT      col.[Name], 
CASE col.[is_nullable] WHEN 1 THEN 'Yes' ELSE 'No' END AS [IsNullable],
CASE col.[is_identity] WHEN 1 THEN 'Yes' ELSE 'No' END AS [IsIdentity],
types.[name] as [DataType],
col.[max_length] AS [MaxLength]
FROM sys.columns col
INNER JOIN sys.types types ON
col.[user_type_id] = types.[user_type_id]
WHERE col.[object_id] = object_id('HumanResources.Employee')
ORDER BY col.[NAME]
GO

> Using IIF
SELECT col.[Name], 
IIF(col.[is_nullable] = 1, 'Yes', 'No') AS [IsNullable],
IIF(col.[is_identity] = 1, 'Yes', 'No') AS [IsIdentity]
,
types.[name] as [DataType],
col.[max_length] AS [MaxLength]
FROM sys.columns col
INNER JOIN sys.types types ON
col.[user_type_id] = types.[user_type_id]
WHERE col.[object_id] = object_id('HumanResources.Employee')
ORDER BY col.[NAME]
GO

> Output of the two queries

image

Shorts - week 3, 2022

Post with links to what I am reading: 1. A very good post on different aspects of system architecture: https://lethain.com/introduction-to-a...