Dreamer. I Love to Build Cool Stuff | Microsoft MVP | Innovator, Architect, Speaker, Blogger | Experience in Microsoft Platforms, .NET, Mobile, Web Apps, Azure, Enterprise Integration, AI | Hacker, Husband, Son, Father
Real time data syncing across user views *was* hard, especially in web applications. Most of the time, the second user needs to refresh the screen, to see the changes made by first user, or we need to implement some long polling that fetches the data and does the update manually.
Now, with SignalR and Knockout, ASP.NET developers can take advantage of view model syncing across users, that’ll simplify these scenarios in a big way, with minimal code. This post discusses how to implement a real time to-do pad, which will sync data across users accessing the application. This means, users can make changes to their tasks (add/remove/update etc), and other users will see the changes instantly. The focus is on the technique, I’m not trying to build a fabulous user experience here.
I know we are tired with To-do examples, but now let us build a To-do application that can sync tasks between you and your wife (or your team mates) in real time, with full CRUD support, and persistence. And yes, we’ll keep the code minimal, and maintainable using a proper View Model (Oh, is that possible in JavaScript?).
So, see this video, and here you can see the changes you apply to the tasks in one screen (adding, deleting, updating etc) you can see that the data is getting synced across multiple users.
We’ll be using KnockoutJs for maintaining a View Model, and will be syncing the View Model across users using SignalR. If you are not familiar with Knockout and SignalR, we’ll have a quick look at both of them on the way.
First Things First
To start with, let us create a new ASP.NET MVC 3.0 application. Create an empty project, I’ve ASP.NET MVC 3 tools update installed. Once you’ve the ASP.NET MVC project created, bring up the Nuget console (View->Other Windows-> Package Manager console), and install the Nuget packages for Knockout and SignalR.
install-package knockoutjs
And SignalR
install-package signalr
Also, do install Entity Framework latest version if you don't have the same, so that we can use the Code first features
Install-Package EntityFramework
If you are already familiar with Knockout and SignalR, you may skip the next two titles and go directly to 'Building KsigDo' section.
Knockout
Knockout Js is an awesome Javascript library that allows you to follow the MVVM convention, to bind your User controls to a JavaScript view model. This is pretty cool, because it allows you to build rich UIs pretty easily, with very minimal code. Here is a quick example that shows how you can bind your HTML elements to a Javascript view model.
Here is a very simple view model.
// This is a simple *viewmodel*
var viewModel = {
firstName: ko.observable("Bert"),
lastName: ko.observable("Bertington")
};
// Activates knockout.js
ko.applyBindings(viewModel);
The attributes are of type ko.observable(..), and if you want to convert the viewModel to an object (where you can send over the wire), you can easily do that using ko.toJS(viewModel). Now, let us bind the above view model to a view. The binding happens in the data-bind attribute, you may see that we are binding the value of the textbox to the firstname and last name variables. When you call ko.applyBindings, Knockout will do the required wiring so that the view model properties are synced with the target control's property values.
<!-- This is a *view* -->
<p>First name: <input data-bind="value: firstName" /></p>
<p>Last name: <input data-bind="value: lastName" /></p>
KnockoutJs is pretty easy to learn, the best way to start is by going through the interactive tutorial hosted by Knockout guys here at http://learn.knockoutjs.com/.
Update: Found that Shawn has wrote a comprehensive post on Knockout, Read that as well
SignalR
SignalR is the “greatest thing since sliced bread” that happened for Microsoft developers recently. (To know why, you can read by post “HTML5 is on a killer spree, may kill HTTP next at least partially”. Anyway, SignalR is an Async signaling library for ASP.NET to help build real-time, multi-user interactive web applications. If you heard about Node, Backbone, Nowjs etc recently, you know what I’m talking about. If not, you’ll know pretty soon though.
The easiest starting point to understand SignalR is, by having a look at the Hub Quickstart example. Have a look at that example and come back.
You can inherit your Hub at the server side from SignalR.Hubs.Hub – and SignalR will generate the necessary light weight Javascript proxies at the client side so that you can make calls to your hub over the wire, even with support for typed parameters. Not just that. SignalR also provides dynamic “Clients” and “Caller” objects in your hub, so that you can invoke a client side method written in Javascript directly via your code in the server side. Pretty smart. And SignalR hides the entire implementation under its nice little APIs.
Building The KsigDo App
Now, let us go ahead and build our KsigDo app. Let us put together the bits step by step.
Task Model For Persistance Using Entity Framework Code First
In you ASP.NET MVC application, go to the Models folder, and add a new code first model file. Our model is very minimal, and as you can see, we have a taskId and a title for a task, and few validation rules defined, like title's length. Also, the completed property decides whether the task is a completed one or not.
public class KsigDoContext : DbContext
{
public DbSet<Task> Tasks { get; set; }
}
public class Task
{
[Key]
public int taskId { get; set; }
[Required] [MaxLength(140)] [MinLength(10)]
public string title { get; set; }
public bool completed { get; set; }
public DateTime lastUpdated { get; set; }
}
The DbContext and DbSet classes used above are provided as part of the EF4 Code-First library. Also, we are using the attributes like Key, Required etc for data annotations, for basic validation support.
TaskHub For Basic Operations
Create a new folder named 'Hubs' in your ASP.NET MVC project, and add a new TaskHub.cs file (No, we are not using Controllers now). And yes, you can place your Hubs any where. Here is our TaskHub, inherited from SignalR.Hubs.Hub class. You may see that we are using this Hub to perform most of the CRUD operations in our Task Model.
public class Tasks : Hub
{
/// <summary>
/// Create a new task
/// </summary>
public bool Add(Task newTask)
{
try
{
using (var context = new KsigDoContext())
{
var task = context.Tasks.Create();
task.title = newTask.title;
task.completed = newTask.completed;
task.lastUpdated = DateTime.Now;
context.Tasks.Add(task);
context.SaveChanges();
Clients.taskAdded(task);
return true;
}
}
catch (Exception ex)
{
Caller.reportError("Unable to create task. Make sure title length is between 10 and 140");
return false;
}
}
/// <summary>
/// Update a task using
/// </summary>
public bool Update(Task updatedTask)
{
using (var context = new KsigDoContext())
{
var oldTask = context.Tasks.FirstOrDefault(t => t.taskId == updatedTask.taskId);
try
{
if (oldTask == null)
return false;
else
{
oldTask.title = updatedTask.title;
oldTask.completed = updatedTask.completed;
oldTask.lastUpdated = DateTime.Now;
context.SaveChanges();
Clients.taskUpdated(oldTask);
return true;
}
}
catch (Exception ex)
{
Caller.reportError("Unable to update task. Make sure title length is between 10 and 140");
return false;
}
}
}
/// <summary>
/// Delete the task
/// </summary>
public bool Remove(int taskId)
{
try
{
using (var context = new KsigDoContext())
{
var task = context.Tasks.FirstOrDefault(t => t.taskId == taskId);
context.Tasks.Remove(task);
context.SaveChanges();
Clients.taskRemoved(task.taskId);
return true;
}
}
catch (Exception ex)
{
Caller.reportError("Error : " + ex.Message);
return false;
}
}
/// <summary>
/// To get all the tasks up on init
/// </summary>
public void GetAll()
{
using (var context = new KsigDoContext())
{
var res = context.Tasks.ToArray();
Caller.taskAll(res);
}
}
}
The Clients and Caller properties are provided by SignalR as part of the Hub class definition. Surprise, these are dynamic objects that you can use conceptually to invoke a client side method written in JavaScript. SignalR does the plumbing using long polling or web sockets or what ever, and we don’t care. Also, as I mentioned earlier, SignalR will generate a client side proxy hub to invoke methods in our above written TaskHub, and we’ll soon see how to use this. For example, when a client invokes GetAll method in the above Hub during initialization, that client invoking the GetAll method (Caller) will get a callback to it’s taskAll JavaScript method, with all the existing tasks.
In the same way, assuming that our Client hub has Javascript methods like taskUpdated, taskAdded, taskRemoved etc – we are invoking those methods using the ‘Clients’ dynamic object, so that when ever an update, add or delete is happening, this information is broad casted all the clients connected right now.
The Main View
Now, let us go ahead and create our client side. Add a 'Home' controller, and an 'Index' action. Create a new 'Index' view. Also, just make sure you’ve the necessary Javascript Script wirings to import Knockout and SignalR libraries (See the code).
Our Index page has got a couple of view models, and a bit of HTML (view). For view models, we’ve a taskViewModel, and a taskListViewModel, as shown below. You may note that our taskViewModel is having almost the same properties as we have in our actual Task model, so that SignalR can manage the serialization/mapping pretty easily when ever we call the methods in our TaskHub.
You can see that in taskListViewModel, we are accessing the $connection.tasks proxy which provides a proxy object to access methods in our TaskHub. Also, we are attaching methods like tasksAll, taskUpdated etc to the $connection.tasks via the this.hub pointer, and these methods are ‘invoked’ from the TaskHub class as we’ve seen earlier to virtually ‘push’ data to the clients.
$(function () {
//---- View Models
//Task View Model
function taskViewModel(id, title, completed, ownerViewModel) {
this.taskId = id;
this.title = ko.observable(title);
this.completed = ko.observable(completed);
this.remove = function () { ownerViewModel.removeTask(this.taskId) }
this.notification = function (b) { notify = b }
var self = this;
this.title.subscribe(function (newValue) {
ownerViewModel.updateTask(ko.toJS(self));
});
this.completed.subscribe(function (newValue) {
ownerViewModel.updateTask(ko.toJS(self));
});
}
//Task List View Model
function taskListViewModel() {
//Handlers for our Hub callbacks
this.hub = $.connection.tasks;
this.tasks = ko.observableArray([]);
this.newTaskText = ko.observable();
var tasks = this.tasks;
var self = this;
var notify = true;
//Initializes the view model
this.init = function () {
this.hub.getAll();
}
//Handlers for our Hub callbacks
//Invoked from our TaskHub.cs
this.hub.taskAll = function (allTasks) {
var mappedTasks = $.map(allTasks, function (item) {
return new taskViewModel(item.taskId, item.title,
item.completed, self)
});
tasks(mappedTasks);
}
this.hub.taskUpdated = function (t) {
var task = ko.utils.arrayFilter(tasks(), function (value) { return value.taskId == t.taskId; })[0];
notify = false;
task.title(t.title);
task.completed(t.completed);
notify = true;
};
this.hub.reportError = function (error) {
$("#error").text(error);
$("#error").fadeIn(1000, function () {
$("#error").fadeOut(3000);
});
}
this.hub.taskAdded = function (t) {
tasks.push(new taskViewModel(t.taskId, t.title, t.completed, self));
};
this.hub.taskRemoved = function (id) {
var task = ko.utils.arrayFilter(tasks(), function (value) { return value.taskId == id; })[0];
tasks.remove(task);
};
//View Model 'Commands'
//To create a task
this.addTask = function () {
var t = { "title": this.newTaskText(), "completed": false };
this.hub.add(t).done(function () {
console.log('Success!')
}).fail(function (e) {
console.warn(e);
});
this.newTaskText("");
}
//To remove a task
this.removeTask = function (id) {
this.hub.remove(id);
}
//To update this task
this.updateTask = function (task) {
if (notify)
this.hub.update(task);
}
//Gets the incomplete tasks
this.incompleteTasks = ko.dependentObservable(function () {
return ko.utils.arrayFilter(this.tasks(), function (task) { return !task.completed() });
}, this);
}
var vm = new taskListViewModel();
ko.applyBindings(vm);
// Start the connection
$.connection.hub.start(function () { vm.init(); });
});
When ever a taskViewModel is created, the instance of taskListViewModel will be passed as it’s ownerViewModel, so that we can invoke the updateTask method of taskListViewModel when ever the current task’s properties are changing. In taskListViewModel, we also have methods like addTask, removeTask etc, which are bound directly to our “View”.
We are creating a new instance of taskListViewModel, and then calling Knockout to do the job of applying bindings with the view. Have a look at the “View” part.
If you look below the Add Task header, you’ll see that we are binding the textbox’s value to the ‘newTaskText’ property of our taskListViewModel, and the form submit to the addTask method in the taskListViewModel. The <ul> is bound to the tasks property of the view model. If you see, tasks property of taskListViewModel is a koObservableArray, which is almost like an ObservableCollection that notifies the bound controls when ever items are inserted/removed in the array.
Adding and Removing items
Have a look at the addTaskMethod in the taskListViewModel, you’ll see that we are creating a new task, and then invoking the ‘add’ method of the ‘hub’, which internally calls the TaskHub’s Add method in the server. In the TaskHub’s Add method, you’ll see that we are broadcasting the added task to all the clients by invoking the taskAdded method in the client side back – and there we are updating the ‘items’ observable array, so that Knockout will internally manage the rendering of a new <li> under the <ul> based on the data template ‘tasktemplate’ (see the above view code where we have the tasktemplate.
Delete also works in the same way, you can see the ‘x’ button is bound to the remove method of each individual taskViewModel, which internally calls the taskListViewModel’s removeTask method to invoke the Remove method in TaskHub using the hub proxy, and from there, the taskRemoved will be invoked on all the clients, where we actually remove the item from the items collection.
Updating an Item:
Once an item is bound to the template, please note that we are subscribing to the change events of a task in taskViewModel. When ever a property changes, we call the updateTask method in the ownerViewModel, which again calls hub’s update method which sends the task to our TaskHub’s update method – thanks to the wiring from SignalR. There, we try to save the item, and if everything goes well, the updated item will be broadcasted from the TaskHub to all clients, by invoking the taskUpdated Javascript method we attached to the hub, where we actually does the updates the properties of the item in all clients.
Conclusion
Surprise, we are done. Very minimal code, very little effort, Great results. Thank you ASP.NET, SignalR, Entity Framework and Knockout. And that is why I love .NET . Happy Coding, but follow me in twitter @amazedsaint and subscribe to this blog.
You may also like these articles on a similar taste.
We’ve already seen HTML5 killing few technologies on the presentation side – Adobe Just killed Flash for Mobile, and Microsoft ‘Positioned’ Silverlight as a tool for LOB apps and Phone apps instead of a cross platform presentation layer.
As most organizations are now focusing on HTML5 as part of their next gen strategy for what ever reasons (mainly cross platform), it is pretty obvious that there is going to be wide spread adoption from all major user agents – and more importantly, a lot more tooling and frameworks will evolve for developing HTML5 applications (You might have already explored previews like Expression Blend for HTML5 if you are in the Microsoft World, along with improved support for HTML5 in VS). The evolution of HTML5 will definitely bring in a radical shift in the way we develop web applications as we have already seen – and a nice little part of the parcel is Web sockets - which allows you to implement full duplex TCP based communication between the user agent (browser) and the server.
The problem with HTTP and existing server stacks
Here is a short description of HTTP from W3C
The Hypertext Transfer Protocol (HTTP) is an application-level protocol for distributed, collaborative, hypermedia information systems. It is a generic, stateless, protocol which can be used for many tasks beyond its use for hypertext, such as name servers and distributed object management systems, through extension of its request methods, error codes and headers [47]. A feature of HTTP is the typing and negotiation of data representation, allowing systems to be built independently of the data being transferred.
HTTP works in a request/response way – The client should always initiate a request to obtain the data, and in other words, the server can never push data real time to client. A common work around is to use HTTP long polling, where the client makes a request, and the server holds the request till some data is available, and pass it back to the client. I believe from Http 1.1 onwards, persistent connections are the default behavior of the HTTP connection anyway – though the response/request HTTP model don’t allow the server to do real-time pushes.
WebSocket is a technology providing for bi-directional, full-duplex communications channels, over a single Transmission Control Protocol (TCP) socket. It is designed to be implemented in web browsers and web servers but it can be used by any client or server application. The WebSocket API is being standardized by the W3C and the WebSocket protocol is being standardized by the IETF.
With web sockets, which are fully duplex, you have some thing state full, which will allow you to build web applications which can satisfy real time requirements. This means better user experience, better speed, and overall better productivity. We’ll see a new range of web applications emerging, including more sophisticated games and better real collaboration tools. We’ll definitely see more matured and domain specific light weight RPC frameworks for servers and clients (As of now, I think frameworks like NowJs/Socket.IO on top of Node and SignalR on to of IIS already has this in their implementation/roadmap in a general way - to wrap web sockets and has a fall back strategy on HTTP long polling if the client is not supporting web sockets yet).
According the Web Socket API spec, when a web socket connection is made,
The headers to send appropriate cookies must be a Cookie header whose value is the cookie-string computed from the user's cookie store and the URL url; for these purposes this is not a "non-HTTP" API.
Anyway, most of the current server stacks and related programming models, including LAMP, IIS/ASP.NET etc is modeled around the normal request/response HTTP stack -and once the focus on Web sockets increases, they need to optimize themselves to handle concurrent connections simultaneously with out affecting the performance. A new age web server may be almost like a re-labeled IRC server which can handle a number of real time connections simultaneously (On contrary, you may also argue that HTML5 web sockets may make IRC servers obsolete as well).
Web Socket API specifications are not yet finalized. And as of now, based on http://caniuse.com – the following client side platforms are supporting Web Sockets specs. Between, I use http://caniuse.com often to see the platform adoption of HTML5 APIs and Semantics.
I think, to some extent, this means a radical shift in the way we write web applications which need real time features. More importantly, you can bend the web in a better way – because you’ve access to a transport layer protocol (TCP) on top of which you can build your own custom/domain centric protocols, instead of getting constrained with the application level HTTP protocol. Also, I am pretty sure that most of the client side agents other than web browsers will also start supporting web sockets in no time.
A Quick word on Server Side Events
As you read this far, it might be interesting to note that HTML5 specifications has another API named server side events (SSE), which allows you to Push data from server to client via an HTTP channel.
This specification defines an API for opening an HTTP connection for receiving push notifications from a server in the form of DOM events. The API is designed such that it can be extended to work with other push notification schemes such as Push SMS.
Anyway, Web Sockets are getting more attraction because it provides more control as it is on top of TCP, and more importantly, it is bidirectional. And what ever you can do with SSE can be implemented using Web Sockets, with a bit of custom code.
Here are few links to follow.
Checkout this example of Web Sockets - This is a quick example that shows how I’m streaming WPF windows over web sockets to a browser, to draw it in a canvas
Happy Coding, but beware, HTML5 is just near your door. Chances are that, pretty soon, almost half of the things you do today with classic HTTP stack will be replaced with wrapper implementations like NowJs or SignalR.
This post is about implementing Chain Of Responsibility design pattern, and few possible extensions to the same. If you are new to design patterns, I suggest you should start with Practically Applying Design Patterns – Thought Process
Coming back to Chain of Responsibility - If you have a scenario where you need to chain multiple handlers to handle an incoming request or command, you better use Chain Of Responsibility.
A typical example is your girlfriend requesting you something – If she is requesting/commanding you something like “Do you want to come with me for my best friend’s Bachelorette party?”, you will handle it directly. But if she is requesting/commanding you some thing like “Buy me a Porsche”, you say “Sorry Honey, I don’t have the money. Better you ask your dad for this, I’ll call him for you” –i.e, you pass the request to the next handler, in this case your girl friend’s Father. To sum up, in the above example, your girl friend is the client who is making the request, and you and your future father-in-law are handlers/approvers who handle/approve her requests. If you cannot handle it, you pass that responsibility to the next handler/approver in the chain.
A Minimal Example
To consider a more formal example, assume a scenario where you’ve a banking system, and you want to implement some kind of Loan approval. The customer may request a loan, and if it is below a specific amount, the cashier may approve it directly. If it is above the specified amount, he might pass the request to his manager for approval.
So you may use Chain Of Responsibility implementation to hand over the request/command to the correct approver. For an example, consider this implementation of the above Bank account scenario. Our business rule is something like, a cashier can approve the request if the amount is lesser than 1000 $$, other wise the approval should be passed to the manager. The manager can approve the request if the amount is lesser than 10,000 $$.
Concrete handlers like Cashier and Manager implements this
Has a reference to the successor to pass the request
Program – The main driver
To the code
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DesignPatternsCof
{
//Request
class LoanRequest
{
public string Customer { get; set; }
public decimal Amount { get; set; }
}
//Abstract Request Handler
interface IRequestHandler
{
string Name { get; set; }
void HandleRequest(LoanRequest req);
IRequestHandler Successor { get; set; }
}
//Just an extension method for the passing the request
static class RequestHandlerExtension
{
public static void TrySuccessor(this IRequestHandler current, LoanRequest req)
{
if (current.Successor != null)
{
Console.WriteLine("{0} Can't approve - Passing request to {1}", current.Name, current.Successor.Name);
current.Successor.HandleRequest(req);
}
else
{
Console.WriteLine("Amount invaid, no approval given");
}
}
}
//Concrete Request Handler - Cachier
//Cachier can approve requests upto 1000$$
class Cashier : IRequestHandler
{
public string Name { get; set; }
public void HandleRequest(LoanRequest req)
{
Console.WriteLine("\n----\n{0} $$ Loan Requested by {1}",
req.Amount, req.Customer);
if (req.Amount<1000)
Console.WriteLine("{0} $$ Loan approved for {1} - Approved by {2}",
req.Amount,req.Customer, this.Name);
else
this.TrySuccessor(req);
}
public IRequestHandler Successor { get; set; }
}
//Concrete Request Handler - Manager
//Manager can approve requests upto 10000$
class Manager : IRequestHandler
{
public string Name { get; set; }
public void HandleRequest(LoanRequest req)
{
if (req.Amount < 10000)
Console.WriteLine("{0} $$ Loan approved for {1} - Approved by {2}",
req.Amount, req.Customer, this.Name);
else
this.TrySuccessor(req);
}
public IRequestHandler Successor { get; set; }
}
//Main driver
class Program
{
static void Main(string[] args)
{
//Customers
var request1 = new LoanRequest() { Amount = 800, Customer = "Jimmy"};
var request2 = new LoanRequest() { Amount = 5000, Customer = "Ben"};
var request3 = new LoanRequest() {Amount = 200000, Customer = "Harry"};
//Approvers, chained together
var manager = new Manager() {Name = "Tom, Manager"};
var cashier = new Cashier(){ Name = "Job, Cachier", Successor = manager};
//All customers request cashier first to approve
cashier.HandleRequest(request1);
cashier.HandleRequest(request2);
cashier.HandleRequest(request3);
Console.ReadLine();
}
}
}
And this is what you’ll see upon execution.
So, you may observe that Loan Requests from different customers are passed to the cashier in the above example, and the cashier in his approve method passes the request to his successor (i.e, the manager) if the amount is higher than what he can approve. The implementation is pretty minimal, as you can see.
We actually have an Abstract request handler implementation IReqeustHandler and two concrete request handlers, Cashier and Manager. Each request handler may hold a reference to the successor. You may see that we are setting the Successor of Cashier as Manager, so if the amount requested his beyond a limit, the cashier may pass it to the manager for his approval.
Dynamically Injecting Approvers
Now, let us take a step back, and think how to implement this in such a way that the approval pipeline is extensible? As of now, our pipeline has two approvers, cashier and manager, and the manager can approve loans up to 10,000. Tomorrow, the Bank may decide that the General Manager can approve loans above 10,000 – and what you are going to do? Make the changes, Recompile the entire application, move it to QA, initiate a full recursion testing, and deploying everything to production? You may leverage a bit of extensibility here, and let us have a look at leveraging MEF (Managed Extensibility Framework) for the same.
I recommend you to go through my introductory posts on MEF if you are not familiar with MEF concepts.
Let us go for a generic implementation, to load and compose the handlers leveraging MEF. Let us generalize the above implementation a bit, and introduce few more general purpose contracts and classes.
IRequest – This contract should be implemented by all requests.
IRequestHandler – Same as earlier. Abstract request handler implementation
ExportHandlerAttribute – A custom attribute to export MEF parts
IRequestHandlerMetadata – Used internally for storing the successor information as a type
RequestHandlerGateway – Does the composition, and passes the request to successors in a chained fashion.
To the code
//Abstract Request
public interface IRequest { }
//Abstract Request Handler
public interface IRequestHandler
{
bool HandleRequest(IRequest req);
IRequestHandler Successor { get; set; }
}
//A custom MEF Export attribute
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ExportHandlerAttribute : ExportAttribute
{
public Type SuccessorOf { get; set; }
public ExportHandlerAttribute()
: base(typeof(IRequestHandler))
{
}
public ExportHandlerAttribute(Type successorOf)
: base(typeof(IRequestHandler))
{
this.SuccessorOf = successorOf;
}
}
//The metadata to tie a handler to next successor
public interface IRequestHandlerMetadata
{
Type SuccessorOf { get; }
}
//A gateway which stiches together the handlers, to accept a request to chain through the handlers
//Note that this does the composition using MEF
public class RequestHandlerGateway
{
[ImportMany(typeof(IRequestHandler))]
public IEnumerable<Lazy<IRequestHandler,IRequestHandlerMetadata>> Handlers { get; set; }
private IRequestHandler first = null;
public RequestHandlerGateway()
{
ComposeHandlers();
//Let us find and keep the first handler
//i.e, the handler which is not a sucessor of any other handlers
first = Handlers.First
(handler => handler.Metadata.SuccessorOf == null).Value;
}
//Compose the handlers
void ComposeHandlers()
{
//A catalog that can aggregate other catalogs
var aggrCatalog = new AggregateCatalog();
//An assembly catalog to load information about part from this assembly
var asmCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
aggrCatalog.Catalogs.Add(asmCatalog);
//Create a container
var container = new CompositionContainer(aggrCatalog);
//Composing the parts
container.ComposeParts(this);
}
//Try to handle the request, pass to successor if required
bool TryHandle(IRequestHandler handler, IRequest req)
{
var s =
Handlers.FirstOrDefault(
h => h.Metadata.SuccessorOf == handler.GetType());
if (handler.HandleRequest(req))
return true;
else if (s != null)
{
handler.Successor = s.Value;
return TryHandle(handler.Successor, req);
}
else
return false;
}
//Main gateway method for invoking the same from the driver
public bool HandleRequest(IRequest request)
{
return TryHandle(first,request);
}
}
Cool. So we have the basic stuff there, keep that handy. Now, to have a Chain Of responsibility implementation, you can simply create the concrete parts and export the same. We’ve the following concrete parts.
LoanRequest – A concrete request
Cashier, Manager, and GeneralManager – Concrete request handlers
You may note that now we can chain the handlers using the Meta data. For example, when you export the manager, you can easily specify that Manager is the successor of Cashier, to approve the request. Similarly, you can specify General Manager as the successor of the Manager. The advantage is, you can simply deploy these components in a loosely coupled manager, and pick them up using the DirectoryCatalog of MEF during re composition.
//Concrete Request
public class LoanRequest : IRequest
{
public string Customer { get; set; }
public decimal Amount { get; set; }
}
//Concrete Request Handler - Cachier
//Cachier can approve requests upto 1000$$
[ExportHandler]
public class Cashier : IRequestHandler
{
public bool HandleRequest(IRequest r)
{
var req = (LoanRequest)r;
if (req.Amount < 1000)
{
Console.WriteLine("{0} $$ Loan approved for {1} - Approved by {2}",
req.Amount, req.Customer, this.GetType().Name);
return true;
}
return false;
}
public IRequestHandler Successor { get; set; }
}
//Concrete Request Handler - Manager
//Manager can approve requests upto 10000$
[ExportHandler(SuccessorOf = typeof(Cashier))]
public class Manager : IRequestHandler
{
public bool HandleRequest(IRequest r)
{
var req = (LoanRequest)r;
if (req.Amount < 10000)
{
Console.WriteLine("{0} $$ Loan approved for {1} - Approved by {2}",
req.Amount, req.Customer, this.GetType().Name);
return true;
}
return false;
}
public IRequestHandler Successor { get; set; }
}
//Concrete Request Handler - Manager
//Manager can approve requests upto 10000$
[ExportHandler(SuccessorOf = typeof(Manager))]
public class GeneralManager : IRequestHandler
{
public bool HandleRequest(IRequest r)
{
var req = (LoanRequest)r;
if (req.Amount < 100000)
{
Console.WriteLine("{0} $$ Loan approved for {1} - Approved by {2}",
req.Amount, req.Customer, this.GetType().Name);
return true;
}
return false;
}
public IRequestHandler Successor { get; set; }
}
//Main driver
class Program
{
static void Main(string[] args)
{
//Customers
Console.WriteLine("Enter Loan Amount:");
var amount = decimal.Parse(Console.ReadLine());
var req = new LoanRequest() {Amount = amount, Customer = "Ben"};
var gateway = new RequestHandlerGateway();
if (!gateway.HandleRequest(req))
Console.WriteLine("Oops, too high. Rejected");
Console.ReadLine();
}
}
And this is what you’ll get. You can see that the request gets dispatched to the correct handler.
I was very skeptical about CQRS (Command Query Responsibility Segregation) some time back, how ever after working on a CQRS implementation for the past few months for a customer in the telecom domain, I see better light. For some reason, there is a wide spread perception that CQRS is only for complex domains, how ever I think any true business system can benefit from CQRS principles. Here are few quick thoughts, mostly rants.
What is CQRS?
The basic idea of CQRS is pretty simple, this is from the CQRS summary post by Greg Young
Starting with CQRS, CQRS is simply the creation of two objects where there was previously only one. The separation occurs based upon whether the methods are a command or a query (the same definition that is used by Meyer in Command and Query Separation, a command is any method that mutates state and a query is any method that returns a value).
When most people talk about CQRS they are really speaking about applying the CQRS pattern to the object that represents the service boundary of the application.
As simple as that. I suggest you to read/bookmark the below posts.
So, most of the discussion happening these days is about the application possibilities and implementation details around CQRS, and these are just few random thoughts around the same, and these are not any pointers for anyone.
For a moment, let us forget what exactly is CQRS, let us see how your system or business normally works. The users or stake holders or external system interact with your system in two ways – basically they’ll ask the system to do something (commands), and they also need to view/visualize the state of the system in different ways (queries). In most businesses, the system will be queried not just for the current state, but also for historical changes – i.e, you need to track the history of changes (as in an audit log) and need special logic to capture intelligence about events happened in the past. Say, to answer like "how many users are removing product x from their cart after adding product y".
You could argue any system that is just CRUD is a database, and yes we can put any decoration on top of it to build some editing features. But any meaningful Business Context involves capturing intent from user, to validate the intent at times, handle it, and provide some meaningful read models to query.
So, I think CQRS allows modeling the domain in a more natural way. You can pick commands directly from the use cases (if well written), and you can focus on what the domain does or what the domain should do when a state change happens, and use this information to construct how different stake holders view the system. In our scenario, we had multiple dimensions/read model snapshots.
Do I need CQRS?
It is all about the ROI, isn't it? Theoretically, you could argue any BC that models a set of business scenarios can be benefited leveraging the CQRS principles, because that means your system will be able to answer a lot of business related questions implicitly. Do you need that or not? That's a business call.
Here is my top three reasons based on my limited exposure towards CQRS based models.
The users or stake holders or external system interact with your system in two ways and if you are specifically focused on capturing the user intent– basically in any system, they’ll ask the system to do something (commands), and they also need to view/visualize the state of the system in different ways (queries).
In case your system will be queried not just for the current state, but also for historical changes – i.e, you need to track the history of changes (as in an audit log in a stereotypical system) and need special logic to capture intelligence about events happened in the past. Say, as I mentioned, to answer like "how many users are removing product x from their cart after adding product y".
Your management/customer thinks it'll add value to them on the long run, i.e, the system will help them have an edge over the competition. Oh yea, you have to sell this to them.
There is going to be a spike in the CapEx, may be because building Task Based/Inductive UIs are more costly than spread sheet like grids/CRUD focused forms where the user has to bring up the entire form to change the status from open to closed or what ever. Other than that, I think the cost is totally dependent on the design and related details, and the way you implement CQRS along with other DDD patterns.
CQRS and Event Sourcing
CQRS can be a simple separation of commands and queries, but I think the real value is if you tie CQRS with Event sourcing - it allows you to capture the system as how it came to the current state, rather than what it is right now. So, you are adding a new dimension to the system, i.e, the time. And you can take snapshots of the system at different times, and then compare it, that is valuable business intelligence. I think we don't need to see the read model as just a static snapshot of the system at a given time - it can even be derived from the state of the system at two different times.
And you can build read models based on multiple dimensions - to answer questions related to the system's behavior as well. For example, a stereotypical system can't answer even simple questions like "how many users are removing product x from their cart after adding product y" with out explicit design to capture the scenario. In a CQRS system this is implicit.
You can plugin a new dimension that constructs a read model to answer the query. About the cost - I think the key is in bringing in the mindset and selling this idea to the stake holders - even if the initial investment is a bit high, that will significantly improve their ROI and place them ahead of the competition.
How ever, the problem is, the world may be too corrupted with people like us, who were trying hard to persist a single state snapshot of the system in a mismatching ER model and then trying to keep it up to date and worrying about all related issues, to further mess it up with audit logs and all other mining crap when business starts asking critical questions.
Based on the recent experience, I’ve got a feeling that REST and CQRS goes well together, and there is a bit to explore there. To start with, they way we implemented Commands in one of the recent system is over a REST API, where the URL scheme represents the commands.
Say, for example, if the user need to close and issue, the end point will be like http://server/issue/close - The end points are used to identify the command handler and pass it to the same. Command handlers are registered in a container, in our case we used MEF to export the command handlers, something like
Message is essentially a key value store as in a dictionary, and this allows us to cope up with versioning. We had a REST based Querying API too. And we were federating the commands to the results/DTOs as in Hypermedia
i.e, here is an example
[ExportCommandHandler("Issue","Close")]
public void CloseIssueCommandHandler(int id) {..}
I couldn't figure out a defined way for the Task Based UI to find out possible commands based on the current state. Probably this is more or less an implementation related aspect and all of us are free to choose. We could do the validation of the command after it is issued, but in some scenarios, it is better to prevent the user from issuing the command in first place.
I.e, let us consider a DTO,
<issue>
<id>1</id>
<description>A bug is trying to hug me</description>
<otherfields/>
<link rel="rc:closeissue" url="/issue/close/1">
</issue>
Now, when a user closed an issue, a CloseIssuecommand has gone in and if the operation succeeds, an IssueClosed event has been logged to our event store - Now, as the issue is already closed, you don't need to (or you should not) provide the CloseIssue action to another user again, because the Issue is already closed by some one.
So, in our scenario, we had some decorators on top of the Query builder to evaluate the current state, so that only the required commands are federated to a returned result. So, the Task Based UI can be more intelligent (and the TB UI is anyway issuing commands based on the DTO information it has).