Sunday, July 6, 2014

Dart/Javascript Interop - Creating a SignalR client wrapper in Dart

I've recently been exploring the idea of using Dart for the client side of my next web project as I think the language lends itself to a more maintainable code base at larger sizes copared to JavaScript. However, due to the large number of frameworks JavaScript already has at it's disposal, it would be silly to not try to leverage those frameworks. One in particular, is the SignalR JS client. I really like SignalR as a technology, it's easy to use and provides great real-time support to your .NET web application. However, the idea of writing my own Dart client from scratch to support two way communication with a SignalR server seems like it would be quite a large effort. So I decided to see how hard would it be to just create a Dart wrapper around the existing JS library.

Example server code

In this example, we should first go over what is on the server. I've built my client separate from the server so I needed to enable CORS support. Strangely, this support in SignalR is in an entirely separate NuGet package, which in my mind, seems a little odd. Make sure you have the installed the SignalR server and CORS NuGet package onto your server project.

Install-Package Microsoft.AspNet.SignalR
Install-Package Microsoft.Owin.Cors

To setup SignalR, you need a Startup class with a [assembly:..] reference to it.

You will also need to register a Hub.


Example in JavaScript

Now, the JS code to access this hub (without JS code gen) is pretty simple and looks like the following snippet.


This is assuming your page is hosted on the same server, SignalR defaults urls, something we are not going to do for our Dart client.

Example in Dart

I wrote the wrapper to try to keep the implementation code as similar to the JavaScript equivalent as possible. 


JavaScript Interop

The enable the code above, I wrote a small Dart package to wraps the connection and proxy objects exposed in the JavaScript library that SignalR provides. So this code still requires that the SignalR JavaScript client is included in the page as well as jQuery.

Wrapping an existing JS library is pretty straight forward, though debugging can be difficult at times, I think the Dart team has done a pretty darn good job with it. Here is all the code that enables the HubConnection and HubProxy classes.




Obviously this doesn't wrap everything in the JS lib, but enough to get two-way communication going for a lot of situations and as you can see above, is pretty straight forward.

Conclusion

Although that Google hasn't announced when the DartVM will be embedded in Chrome, it probably isn't far off. It has been said that JavaScript is the assembly language of the web, and for asm.js, I think that analogy is pretty damn close. After writing some JS interop, it really reminded me more of a less painful COM interop from .NET. All in all, I think people are going to want to leverage this feature a more going into the future. I still think Dart is moving in the right direction, more so than TypeScript and others. And as Dart usage continues to grow into Servers, it's going to make more sense to use it more for clients as the DartVM grows in support. 

Saturday, April 26, 2014

AngularJS - Exposing a Directive API

I've been doing a fair bit of AngularJS development over the past 18 months (currently full-time) and I've come across a pattern I've found my self using a fair bit. For the most part it seems to hold water and make my life easier, but I don't know if that's just a short term gain that will come back to bite me (or someone else) in the near future. I also wanted to post about it to see if it either helps any one else or invokes someone to point out why it's a bad idea.

I'm very conscious of how easy it is to generate a maintenance burden when building an application. Lots of developers, including myself, have been forced to maintain 'legacy' applications and have to work with your decisions for years.

So the pattern started from a suggestion on the angular documentation when wanting to expose an API to other directives.
This advice is pointing to the use of 'require: "^fooParent" directive and the subsequent injection on the link function like so.

Once you have this, your html structure goes something like ...

This is obviously a not a useful example, but should illustrate the basics around using a parent directive's controller. Once the angular $digest is processed, the alert will show "hello fred".

What I've done recently with this idea is more widely expose the controller of useful directives with the following.

When the event is listened for on another controller, you can have access to the specific instance of directive controller to fire events explicitly without using chained $braodcast/$on methods. Also requires the use of the 'scope' property on a directive enforcing an isolated scope, which is a good thing if you are producing reusable directives.

I have found this useful when combined with the idea that no state should live on an angular service* (unless very good reason for it). The directive should hold any state required for its main purpose. Remember, there is a pretty good chance some one will ask to support multiple instances of your directive on the same page.

Any thoughts? Warnings? Advice? Let me know in the comments.

Thursday, January 23, 2014

ServiceStack + AngularDart - Getting Started

Over the past couple of months, I've been spending more time with Dart and trying to get my head around how to use it in my current set of favourite tools and workflows. I've also been working on a site to share and collaborate on Tiled map editor maps called 'TiledStack'. The site is currently written in AngularJS and I have ~80% of the functionality I want the site to have is done. The site is not overly complicated, ~10 controllers, a few services and bunch of templates so far, however the I've built a Tiled map previewer in Dart which works great on its own, but is.. awkward when integrated in a straight JS web application. This is primary due to the required flow of a Dart web application. This awkwardness forced a UX that I really didn't like if I wanted an integrated map preview to work with my current AngularJS site.

So, after a bit of indecisiveness (and a friendly prompt), late last year I decided to give it a crack. I am also writing another post that deals with the guts of converting an AngularJS site to AngularDart, but first I would like to document what I found when getting started with Dart and ServiceStack/ASP.NET server.


AngularJS Developers

A great starting point for getting into to AngularDart is a post 'AngularDart for AngularJS developers' by Victor Savkin.

Dart new comers

In this brief tutorial I'm not going to go over how to setup a Dart application, if you are only just getting into Dart, here is a list of some great resources to get you started.


Angular new comers 

If you are new to AngularX, but interested in this workflow and with AngularDart, this StackOverflow answer is a great resource.

Workflow

There are quite a number of ways of setting this up for a Dart client and a .NET server but all of them involve introducing an additional IDE. My personal choice is WebStorm by Jetbrains if you are running everything with dart2js. WebStorm has some awesome features and is worth trying out. Although, since Webstorm is commercial and not free, I will be using the Dart editor for this example. First, lets get Visual Studio and our web application ready.

Note: Hopefully in the future, they might include a way to both compile and debug Dart code in Visual Studio, but I wouldn't hold your breath. (At the time of writing, I couldn't find a way to debug Dart code in Visual Studio even though, Dart produces a js.map file, please ping me if you find a way!)


Setting up Visual Studio

This might not be the most ideal setup for everyone, but I've focused on the need to be able to quickly iterate on both the server side (ServiceStack) as well as the client. Thankfully the Dart editor only cares about folder structure, so to make things simple and to let IIS local or express deal with the hosting of all files, we are going to share the folder workspace between Dart and Visual Studio. 

One problem you will notice if you are debugging in Dartium, is that '.dart' files are getting 404 errors. You will need to do two things to fix this.


  1. Add all the .dart files you are using to your Visual Studio project. This means when you publish or go to debug, they are copied along with the rest of the application. For good measure, also set 'Copy Always' on the file.
  2. Get IIS to recognise the MIME type of the '.dart' files to allow them to be accessed via the web server. Here is some config which should do the trick.

If you have ServiceStack handler setup to catch all requests (eg, "*"), you will need to allow the use of the 'dart' extension in config (Thanks Henrik!).

Setting up Dart Editor

Now that your Dart client files are shared with Visual Studio, you are going to want to test them in Dartium. 

You'll need to add the directory of your ASP.NET project as a Dart project in the Dart Editor.


You'll then want to add a 'Launch' configuration from the Dart Editor which points at the local URL of your ASP.NET services. Also, the source location should match your correct Dart project for the client you want.




Now, we have VS debugging and we run our new Dart Runtime configuration and...



Awesome, debugging native Dart with a ASP.NET backing! This technique should also work for any ASP.NET hosted data source, Web API, SignalR, WCF (Please no), but if you are working with .NET and building web services I highly recommend checking out ServiceStack.


Now, there is obviously a lot more detail into getting an existing AngularJS website ported across to AngularDart. It is also worth noting that AnuglarDart is under heavy development (which is awesome), so some things might be missing or changing. I will be continuing to learn more of AngularDart and Dart in general as so far I am loving the development community and tools they building. If you haven't already, go grab their tools and get started! :)