All Posts Filed in ‘ASP.NET MVC

Post

Duplex communication in ASP.NET MVC with Domain Events

1 comment

We are going to talk about duplex communication in ASP.NET MVC web apps, without Flash, Java, SL or anything like that. I assume that you have a good understanding of comet techs because we’ll look into a ready-to-use library so most of the hard things are abstracted away. This library is PokeIn and I use it as the base library to provide real-time things on my gaming site fumind.

This is not a how-to-do-it step-by-step tutorial but you may find it interesting if you are looking around for concepts related to the topic. 🙂

I’m going to write about solutions I used to provide these real-time updates and gameflow. The site provides gomoku and gomoku-alike games so don’t expect some fancy action game, these are strictly turn-based stuffs. Because of this we don’t need really fast solutions, so we can go with (or fall back to) classic comet solutions, as the speed of a quick ajax call is good enough for our needs.

Our plan is the following:

  1. Abstract the comet communication away
  2. Implement domain events to keep things simple
  3. Forward domain events to comet listeners

All the three point is about single responsibility and abstraction. (1) We don’t want to tie our code to a specific comet solution so we need some kind of abstraction which is PokeIn in our case. (2) We don’t want to mess up our MVC actions with PokeIn calls but we need a consistent way to notify our system that something happened so if anybody interested in it will get a notification and can handle it in a separate component. (3) After we have domain events we can write listeners which can directly notify the PokeIn clients.

The first one is really easy as we only have to setup the PokeIn library (you can find concrete examples on the PokeIn website). The second requires some foreseeing because this is the base of the two-way communication. Simply put, we expect to see almost the same things in the same moment for all the players and observers. To achieve this in a consistent and maintainable way I dedicated two channels for the communication in the case of real-time things:

  1. Incoming actions
  2. Outgoing events

Incoming actions are plain MVC actions and they will return an OK signal every time it succeded or some kind of error message if something went wrong. These actions will raise domain events so a listener can notify everybody on the outgoing channel, which is PokeIn. This is the key. Because nobody receives the updates directly as the action response we can treat everybody equally when updating the clients. This will lead to a predictable environment which is good for maintainability.

As you may see it has several seams where I can hook in the functionality. I can write my incoming actions and I don’t need to care about any update to the client, I can focus on the action. I can write my domain event listeners separately from my MVC actions so I can focus on only the client selection and notification for every kind of domain events. I can listen on everything on the client side without changing anything on the server side. This is possible because I route through every PokeIn callback on a single JavaScript function and from my custom code I only subscribe to this central callback point then every subscriber can decide if it should do anything with the given information.

Let see some code from the fumind.com codebase. One of the most important parts to achieve what I’m talking about is to create the concept of the domain events. You may find several definitions on the internet, I use it as a mediator pattern implementation.

So for example when somebody makes a move on fumind this action will controll the flow:

[HttpPost]
[UnitOfWork]
[RestrictToAjax]
[ValidateAntiForgeryToken]
public ActionResult MakeMove(MakeMoveViewModel moveViewModel)
{
	Game game = Enter(moveViewModel.GameID);

	var user = _profileService.CurrentUser;
	var context = new MakeMoveContext(game, moveViewModel.Position, user);

	var result = _gameFlow.MakeMove(context);

	if (result == GameFlowActionResult.TimeOver)
	{
		OnSuccessfulUoW = () => EventBroker.Current.Send(this, new TimeOverPayload(game));
		_logger.Info("Time over in game: {0}", moveViewModel.GameID);
	}
	else if (result == GameFlowActionResult.Success)
	{
		OnSuccessfulUoW = () => EventBroker.Current.Send(this, new MoveMadePayload(game, game.LastMove));
		_logger.Info("move made in Game: {0}, Position: {1} by {2}", moveViewModel.GameID, moveViewModel.Position, user.UserName);
	}
	else
	{
		_logger.Warn("Move failed in game: {0}, Position: {1} by {2}", moveViewModel.GameID, moveViewModel.Position, user.UserName);
	}

	Exit(game);

	return Json(Constants.AjaxOk);
}

There are several things in this snippet which aren’t really relevant but I wanted to post the whole thing to make it clear how I made it. You can see things highly related to the makemove process but what is important is the response and the way unit of work helps us here. We declare this action as a unit of work and we respond to the client that we have succeeded:

return Json(Constants.AjaxOk);

Of course only if we really succeeded. This is the incoming part of the flow. An extension point in this code is the OnSuccessfulUoW which is declared in a base controller and you can assign an action to it. This will only run if the whole unit of work succeeded. This indirection is important to avoid false notifications so every client will stay valid. As you can see I call into the EventBroker ambient context inside this callback so basically when the UoW succeeds it will raise a domain event:

OnSuccessfulUoW = () => EventBroker.Current.Send(this, new MoveMadePayload(game, game.LastMove));

With this we are over the first step, we have the action and it has only one responsibility: delegating the makemove attemp to the domain logic. We are handling the updates in a subscriber which listens to the MoveMadePayload. 

Some words about the EventBroker:it based on the Unity DI container so if you ever want to subscribe to a domain event you need to implement the IEventSubscriber<TPayload> interface and register it:

container.RegisterType<IEventSubscriber<MoveMadePayload>, MoveMadeSubscriber>(typeof(MoveMadeSubscriber).FullName);

And the EventBroker will resolve it:

public class UnityEventBroker : EventBroker
{
	private readonly IUnityContainer _container;

	public UnityEventBroker(IUnityContainer container)
	{
		_container = container;
	}

	public override void Send<TPayload>(object sender, TPayload payload)
	{
		var subscribers = _container.ResolveAll<IEventSubscriber<TPayload>>();
		if (subscribers == null) return;
		foreach (var subscriber in subscribers)
		{
			subscriber.Receive(sender, payload);
		}
	}
}

This can be (and will be) improved to handle when a listener throws an exception, but it’s ok for now.

So basically all domain event works because this event broker. You can easily see how we can subscribe to one or more event.

public class MoveMadeSubscriber : IEventSubscriber<MoveMadePayload>
{
	public void Receive(object sender, MoveMadePayload payload)
	{
		//define clients
		//build update data-transfer-objects (dto)
		//notify pokein listeners:
		//var json = PokeIn.JSON.Method("mindline.pokein", dto);
        //CometWorker.SendToClients(viewers.ToArray(), json);
	}
}

It really doesn’t worth to include the whole makemove notification logic here so I just wrote the steps as comments. Of course we need to define the PokeIn clients to update (we can define different branches too, e.g. for makemove I define observers and players separately), we need to build up our dto (data transfer object, I build up slightly different dtos for observers and players) and call into the PokeIn library as you can see.

The only thing left is the client extension point. You can see in the subscriber that we define the mindline.pokein javascript function as the client side endpoint. I use TypeScript as JavaScript preprocessor, but this is really very simple:

/// <reference path="../typings/jquery.d.ts"/>

declare var PokeIn;

module mindline {

    var listeners: { (any): void; }[] = new any[];

    export function addPokeInListener(listener: (any) => void ) {
        listeners.push(listener);
    }

    export function pokein(payload: any) {
        $.each(listeners, (k: any, listener: (any) => void ) => {
            listener(payload);
        });
    }
}

So anybody can hook into this client side root point and can handle any PokeIn calls, such as our makemove action.

I hope you see the gained values of this architecture:

  • I can easily replace PokeIn with another library, it can work with websockets too
  • I can work on my action logic and I don’t need to think about the comet logic meanwhile
  • I can write as many domain event subscriber as I want so I can easily extend the behavior of the existing application
  • I can hook into any comet callback on the client side without modifying any line of the existing code
  • I can encapsulate the complete game flow on the server side so the server controls what you see
  • Real-time comet callbacks are treated exactly the same as if you need to update the clients due to a scheduler event (time over for example), so it’s easier to maintain the code (consistency).

You can do duplex communication in a lot of ways but I think this one is really simple for starting off and provides a consistent environment to deal with the upcoming tasks. And it is reliable :).

What do you think about it?

Post

DeliveryTracker with ASP.NET MVC 4 RC

15 comments

Well, this blog post is about how to make SPA work with RC. The discussion started at http://aspnetwebstack.codeplex.com/discussions/358133

My plan is to share experiences with the SPA (which is a little bit paused now by the team), so don’t expect a complete guide about it now, this will be a series of posts as we move forward and resolve new issues.

As you may already know, SPA is removed from the ASP.NET MVC 4 stack and continued as a separate project. Another problem is the pause on it, so it’s a very unstable area. New problems come day-to-day and old ones get resolved. For example when I first wrote to the codeplex discussion thread about that we resolved the incompatibility between SPA and RC we had some server side problems that disappeared with the current nightly build, but we don’t have OData filters now :).

In this article I will try to make the DeliveryTracker work with the latest MVC builds. If you need the OData filters with SPA right now, you should go with an older changeset (as we do) or another OData lib. For more information check out this thread: http://aspnetwebstack.codeplex.com/discussions/359229

One more thing before we dive into is that we don’t really use EntityFramework and we didn’t explore everything about this stack. Ahh, and this is my first blog post btw. 🙂

Ok, first of all, you will need the DeliveryTracker sources: https://github.com/SteveSanderson/DeliveryTracker

To get the latest MVC nightly builds follow the instructions here: http://blogs.msdn.com/b/henrikn/archive/2012/06/01/using-nightly-asp-net-web-stack-nuget-packages-with-vs-2012-rc.aspx

You will also need the asp.net webstack sources, because the SPA related packages don’t have nuget builds: http://blogs.msdn.com/b/henrikn/archive/2012/04/09/getting-started-with-asp-net-web-stack-source-on-codeplex.aspx

If you got all the stuff then open up the DeliveryTracker solution. You will see that it has the beta MVC packages delivered with it. Update the following ones from the nightly source:

  • ASP.NET MVC 4
  • Web Api Client
  • Web Api Core
  • Web Api Web Host

If you try to run the solution now you will get an application error. This is because the Web Api changed since the beta SPA.

Let’s do some changes!

We need four components for our SPA solution:

  • System.Web.Http.Data
  • System.Web.Http.Data.EntityFramework
  • System.Web.Http.Data.Helpers
  • upshot.js

You can find these packages in the aspnetwebstack source, but now they belong to the Microsoft.* namespace (probably because they continue SPA as a single project).

We will create 3 new projects inside our DT solution and clone the following 3 from the latest:

  • Microsoft.Web.Http.Data
  • Microsoft.Web.Http.Data.EntityFramework
  • Microsoft.Web.Http.Data.Helpers

This is because we probably have to make some changes to make it work or to keep our solution working at the next nightly update (not absolutely necessary now, but it’s safer).

Open up the Runtime.sln (which comes with the latest sources), and check out the Microsoft.Web.Http.Data project. There you will find some linked files in the Common folder so don’t forget to copy those too.

Include the files and do the same with the Microsoft.Web.Http.Data.Helpers and System.Web.Http.Data.EntityFramework.

After you have the sources in the DT you probably have to add nuget packages to the new projects too, such as

  • ASP.NET MVC 4
  • Web Api Client
  • Web Api Core
  • Web Api Web Host

And some reference from the .NET:

  • System.Runtime.Serialization
  • System.ComponentModel.DataAnnotations

If I missed something here then you will need to figure out it yourself (or ask me in a comment), but I hope this list is complete.

The next few steps are temporary solutions, but this whole thing we do here is temporary anyway. So when you try to build it you will get a lots of internal usage error, but who needs internal protection while our goal is to hack around the problems? So change them to public. Do it everywhere the compiler complains about it.

Another problem you will face here is the resource accessing in Errors.cs, you can figure out what’s going on here if you want but I don’t care about the concrete error resource now (it’s really a temporary solution), just change it like in the attached picture.

I don’t really remember, but there is a

using System.ComponentModel.DataAnnotations.Schema;

directive somewhere in the Microsoft.Web.Http.Data that we don’t need and the compiler can’t find it. If you have ReSharper then it’s more easy.

You should have a successful build now (and I hope you have!).

Ok, now we have a DT with the latest MVC and 3 SPA related projects around it. You have to remove the old references from DT and add our new projects:

  • System.Web.Http.Data
  • System.Web.Http.Data.EntityFramework
  • System.Web.Http.Data.Helpers
  • System.Web.Http.Data.Helpers2

The problem now is that the new code has a different namespace. So change them! (System.* -> Microsoft.*)

Delete EntityFramework and install a new one from nuget because we use a newer one in Microsoft.Web.Http.Data.Helpers and we don’t want version missmatch errors.

Also we have to update our namespaces in our web.config files (in the normal and under the Views too).

Change
<add assembly=”System.Web.Http.Data.Helpers, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35″ />
to
<add assembly=”Microsoft.Web.Http.Data.Helpers” />

and under the Views
<add namespace=”System.Web.Http.Data.Helpers” />
to
<add namespace=”Microsoft.Web.Http.Data.Helpers” />

Ok, the code is ready and it should run now (we will have client side errors).

The new server side code generates a different result and our upshot.js is from the beta package. We need to update and fix that too.

Check out the SPA project in the Runtime solution. Upshot made up from different components, so you have to build (combine) the files.

When I made this step for us, the upshot.js had some incompatibility with the current server code, but we will check out what’s the situation now.
I made a little cmd tool to combine the files, you can find the source code here. Copy the exe into the SPA folder and run it. You should have an upshot.js now.


Overwrite the original with it and change the path in the _SpaScripts.cshtml partial.

Well, upshot still has incompatibility problems, so lets fix them. The main difference between the old and the new json pushed by the server is the structure, you can inspect it.

The other is the type handling. I’m not going to write about them one-by-one, you can download the fixed upshot.js and the script file which contains the actual fix functions here.
In the upshot.js I have marked the fixed parts with a comment: //FIX, so you can check out them.
You have to include the SPAHacks.js before upshot to make it work. Refresh the page and voila.

This is it. I hope everything worked out, but if not, you can always ask in comments.

As you can see it’s not a fail proof way to build applications, so I suggest to wait until a stable release comes out. If you don’t want to wait (like me) you can play with it, and I’m going to write more posts when we have more problems.