The Problem Solver

Tell me and I will forget
Show me and I will remember
Involve me and I will understand
- Confucius -

Google Ads

This Blog

Syndication

Search

Tags

News





  • View Maurice De Beijer's profile on LinkedIn

Community

Email Notifications

Explore

Archives

November 2011 - Posts

Services are becoming more important with richer HTML5 style applications. But by default the browser will let you call into a service on the originating domain but not another one. And that means you have to include all your services one the same domain, not very practical. And worse if you want to use a 3rd part service you can’t call this directly from the your JavaScript code.

A technique that has been used for quite some time to solve this problem is JSONP. Basically when you are doing a JSONP style call the request is done by adding a DOM element to the page instead of using the XMLHttpRequest object. While JSONP works it has a number of drawbacks in that you can only do a HTTP GET and if there is an error you will not get any feedback, instead you simply never get a response.

The reason XMLHttpRequest doesn’t work by default is that the browser blocks the result as a security feature. If we open up Fiddler we actually see the request and response as expected, it’s the browser that never passes it back the calling JavaScript code.

The new HTML 5 Cross-Origin Resource Sharing, aka as CORS,  fixes this problem by allowing our code to call into services on other domains with full security still being enforced by the browser.

 

To demo CORS I am using two real simple ASP.NET MVC applications. One of these contains a simple JSON action method and both sites call this same controller action method to retrieve the JSON and display it.

   1: public ActionResult Data()
   2: {
   3:     return Json(new
   4:     {
   5:         firstName = "Maurice",
   6:         lastName = "de Beijer",
   7:         now = DateTime.Now.ToLongTimeString()
   8:     }, JsonRequestBehavior.AllowGet);
   9: }

The ASP.NET MVC view used for both sites is almost identical. There is no difference in the JavaScript, the only difference is in the header so we can distinguish between the two sites.

   1: @{
   2:     ViewBag.Title = "Cross-Origin Resource Sharing";
   3: }
   4: <h2>
   5:     Cross-Origin Resource Sharing call</h2>
   6: <button id='btn'>
   7:     Load data</button>
   8: <pre id='data'></pre>
   9: <script>
   1:  
   2:     $(function () {
   3:         $('#btn').click(function () {
   4:             $.ajax('http://localhost:6688/home/data').then(function (data) {
   5:                 $('#data').text(JSON.stringify(data));
   6:             }, function (e) {
   7:                 $('#data').text(JSON.stringify(e));
   8:             }); ;
   9:         });
  10:     });
</script>

If I open both sites in the browser and try to run the code I get these results. The image on the left is the page on the same side as the service and the image on the right shows the results of the cross domain call.

image

image


Its clear that the cross domain request didn’t work as it came back with an error status

{"readyState":0,"responseText":"","status":0,"statusText":"error"}

In order for this to work there is nothing we have to do to the JavaScript or HTML. Instead we have make a change to the HTTP headers of the response returning the JSON data. The minimum we need to do is add the Access-Control-Allow-Origin header to let the browser know HTML pages originating from which site can request this data. If you want to allow everyone access you can simply specify “*”, alternatively you can specify a specific domain.

So with a minimal change to the service this works just fine.

   1: public ActionResult Data()
   2: {
   3:     Response.AddHeader("Access-Control-Allow-Origin", "*");
   4:     return Json(new
   5:     {
   6:         firstName = "Maurice",
   7:         lastName = "de Beijer",
   8:         now = DateTime.Now.ToLongTimeString()
   9:     }, JsonRequestBehavior.AllowGet);
  10: }

image

You can get far more control though. There are a number of other HTTP headers, both on the request and response, you can use to fine tune the behavior of CORS. More complex scenarios actually result in multiple calls being made behind the scenes, first a preflight request is made to check for the required permissions and only when that is satisfied the actual request is made.

 

All together CORS is a real nice feature to have. As usual the only problem is that Internet Explorer, even IE 10, doesn’t support it Sad smile Check CanIUse.com for support details.

Enjoy!

 

www.TheProblemSolver.nl
www.dotnetevents.nl

Posted by Maurice | with no comments
Filed under: , , , ,

Afgelopen vrijdag bracht de koerier mijn nieuwe telefoon, een Nokia Lumia 800 telefoon met Windows Phone 7 Mango als OS. En die heb ik dit weekend eens flink onderhanden genomen om te kijken of hij nu echt zo goed is als iedereen vindt en vooral of het beter is dan mijn huidige iPhone.

De hardware.

Ik kan er kort over zijn. Nokia heeft hier een hele mooie telefoon gemaakt. Hij is prachtig afgewerkt met een heel mooi helder scherm. Het eerste wat opviel is dat de het standaard blauw anders is dan de Samsung Omnia die we ook al in huis hebben. Dat is geen verschil in het scherm maar het blijkt dat Nokia een extra kleur blauw toegevoegd heeft, Nokia blue, en dat ziet er best mooi uit. Dat is overigens niet de enige Nokia extra die er op de telefoon aanwezig is, zo hebben ze ook extra ringtones en software, meer daarover later, standaard op de telefoon geïnstalleerd. De eerste indruk is ook dat de batterij een stuk langer meegaat dan bij de iPhone maar dan moet ik wel toegeven dat ik het niet echt getest heb, het is maar een indruk. Zo heb ik de hele zondag aardig wat geinternet, een half uur gereden met de Nokia Rijden en de GPS aan en een paar uur naar Nokia Music zitten luisteren en toen was de accu nog niet leeg.

Waar die batterij-winst mee gehaald wordt weet ik niet, ik heb begrepen dat het voor alle leveranciers van telefoons, en de software die er op draait, een grote uitdaging is om de batterij zo lang mogelijk mee te laten gaan. Het is overigens niet mogelijk om een Nokia Lumia 800 open te maken en de batterij te vervangen dus extra stroom zal net als bij een iPhone uit een extern juicepack moeten komen.

Over het algemeen voelt de telefoon heel solide aan. En voor het geval dat komt er standaard ook nog een beschermende hoes omheen. Of dat echt nodig is weet ik niet, ik heb begrepen dat de telefoon van hetzelfde materiaal gemaakt is waar veiligheids helmen van gemaakt worden en het glas, dat door de hoes niet bedekt wordt is ook kraswerend. Maar in de auto bleek de hoes al een leuk antislip voordeel te hebben en het betekent ook dat de knoppen aan de zijkant niet meer uitsteken en dus minder snel per ongeluk ingedrukt worden.

 

Windows Phone 7 Mango

Ik ben erg te spreken over de Windows Phone 7 Mango software. Het werkt snel en makkelijk, net als iOS op de iPhone. Maar wat ik een groot pluspunt vindt is dat je op de levende tegels al een hoop informatie kan vinden en vaak niet eens de applicatie op hoeft te starten. En dan bedoel ik niet alleen het aantal ongelezen emails maar dingen als Buienradar waar ze al een klein recent overzicht van de buien laten zien op de tegel en je zo snel kan zien of het überhaupt de moeite waard is om de applicatie op te starten en verder te kijken. Veel applicaties bevatten dit soort levende tegels om snel informatie te krijgen. De huidige trend van sociale media zoals Facebook en Twitter is ook overal door de telefoon geïntegreerd en voor veel dingen is niet eens een extra applicatie nodig. Ook handig is dat je contactpersonen in groepen in kan delen en dan zo de updates per groep kan bekijken.

Over contactpersonen gesproken. Om mijn mail, agenda en contactpersonen te beheren gebruik ik Google Apps. En dat werkt prima samen met de  Windows Phone 7, er is een optie om een Google account toe te voegen en alles werkt gewoon. Ook afspraken op de telefoon in de agenda zetten synchroniseert prima terug naar het Internet, wel even in de goede agenda zetten natuurlijk.

Wat ook makkelijk is dat je op het lockscreen al infomatie als aantal ongelezen emails en volgende afspraak kan zien en de muziek speler kan bedienen zonder de telefoon te moeten ontgrendelen.

Net zoals bij de iPhone zijn er veel appjes die je kan downloaden van een centrale marketplace. Het zijn er voor de Windows Phone 7 zeker nog niet zoveel als er voor de iPhone beschikbaar zijn, en ik mis er nog een paar, maar er zijn er al 35.000 dus er is veel te halen. En dit aantal zal alleen maar groter worden. De belangrijke populaire apps als NU.NL, Buienradar, WhatsApp, Runkeeper, Wonder Reader (voor Google Reader) en Trip-It zijn allemaal beschikbaar. Een paar die ik nog mis zijn de ANWB, Appie of Instapaper maar het zal een kwestie van tijd zijn voor die ook beschikbaar zijn. Ook aan spelletjes is geen gebrek en zijn populaire namen als Angry Birds en Fruit Ninja zijn allemaal beschikbaar.

 

De extra Nokia software

Nokia heeft een paar extra applicaties op de telefoon gezet. De Nokia Kaarten applicatie die er nu op staat is nog niet de echte en stuurt alleen naar de marketplace. De echte komt binnenkort, als de telefoon in de winkel verkrijgbaar is, vanzelf via de marketplace binnen. Nokia Kaarten wordt overigens gratis beschikbaar voor alle Windows Phone 7 gebruikers, ook die met een ander merk telefoon

Daarnaast is er Nokia Music die naast een groot aanbod van commerciële muziek ook het gratis mix-radio bevat waar iedereen zonder extra kosten naar een groot aantal muziek kanalen kan luisteren. Op dit moment wordt de muziek nog op het moment van afspelen binnen gestreamed maar binnenkort moet er een update komen waar de muziek ook opgeslagen en offline afgeluisterd kan worden. Zo zit ik nu naar het jaren 80 rock channel te luisteren.

 

Een andere nuttige app die ik vandaag eens getest heb is Nokia Rijden, gesproken navigatie software voor in de auto. Je kan hiervoor kaarten van een groot deel van de wereld downloaden en op je telefoon bewaren. Op dit moment heeft deze applicatie een beperking dat je een data verbinding nodig hebt om de bestemming te zoeken maar dit moet binnenkort ook offline werken. Overigens vond ik een menu optie met de titel "Best inst" ook niet helemaal duidelijk om de bestemming op te geven, misschien iets met een vertaling? Wat hierbij wel best handig is dat je een mooi hoesje voor de de telefoon krijgt en dat bij daarmee mooi tegen het dashboard blijft staan. Dat hoefde ik met mijn iPhone niet te proberen, in de eerste bocht was ik hem kwijt. Toch waren de ervaringen met Nokia Rijden niet puur positief. Zo hebben we in het centrum van Zoetermeer een tunnelbak waar je een druk stukje kan passeren, daar heb je geen stoplichten en mag je zelfs 70 Km/uur rijden. En waar TomTom die feilloos weet te vinden wou Nokia Rijden toch bovenlangs waar je 50 Km/uur mag en 3 stoplichten moet passeren, toch jammer. Iets wat ik ook miste is dat TomTom me waarschuwt als ik te hard rij, iets wat Nokia niet doet. Maar daar staat tegenover dat ik Nokia Rijden wereldwijd kan gebruiken en mijn telefoon toch al bij me heb.

 

 

Conclusie

Alles bij elkaar ben ik heel tevreden met de Nokia Lumia 800. De hardware is perfect en Windows Phone 7 voelt lekker aan. Op de extra Nokia software, vooral Nokia Rijden, valt nog wel wat aan te merken op dit moment maar ik weet dat het belangrijkste probleem, een data verbinding nodig hebben om de bestemming op te geven, binnenkort opgelost is. De indrukken van dit eerste weekend zijn dan ook zo dat ik niet bepaald terug verlang naar mijn iPhone, die kan de kast in, maar dat de Nokia Lumia 800 mijn hart gestolen heeft!

 

En wil je meer weten over de Nokia Lumia 800 en wat Nokia allemaal van plan is? Luister dan eens naar deze podcast.

 

www.TheProblemSolver.nl
www.dotnetevents.nl

Posted by Maurice | with no comments
Filed under: , ,

In previous blog posts I wrote about using Server-Sent Events so send data from the server to the browser. This works but has the drawback that it is a one way messaging from the server to the browser. There is nothing preventing you from doing ajax style calls back to the server but basically you are using 2 connection. The big plus for Server-Sent Events is that is use standard HTTP connections so the infrastructure is no problem.

 

WebSockets

Sometimes you want more flexibility of duplex communication and this is where WebSockets come in. Opening a connection from the browser is simply a question of instantiating a WebSocket object and passing in the required URL. The difference is this time we are not using HTTP but the WS scheme so the connection URL looks something like ws://api.myserver.com/chatService. Sounds simple enough but as WebSockets are relatively new you do run a very real risk that some of the infrastructure that works fine with HTTP request will not work with WS requests. But for a demo on a local machine that is no problem Smile

 

The client code

The code on the client is actually quite simple. First we new up the WebSocket and we start listening for onmessage events. There are a few more events that are interesting:

  • The onopen event fires when the connection is opened
  • The onclose event fires when the connection is closed
  • The onerror event that fires when something goes wrong.

To send data you use the send() method that takes a single string to send to the server. Hint: Use JSON.stringify() to turn you rich object into a string.

I wrote a very simple chat client to demonstrate how to work with WebSockets.

image

The complete JavaScript in the page is as follows:

   1: function displayMessage(msg) {
   2:     $('<li>').text(msg).appendTo('#messages');
   3: }
   4:  
   5: var WebSocket = WebSocket || MozWebSocket;
   6: var myWebSocket = new WebSocket("ws://localhost:8181");
   7: myWebSocket.onopen = function (evt) {
   8:     $('#btn, #name, #msg').attr('disabled', '');
   9:  
  10: };
  11: myWebSocket.onmessage = function (evt) {
  12:     var data = JSON.parse(evt.data);
  13:     if (data.name === $('#name').val()) {
  14:         displayMessage('(me): ' + data.msg);
  15:     }
  16:     else {
  17:         displayMessage(data.name + ': ' + data.msg);
  18:     }
  19: };
  20: myWebSocket.onclose = function (evt) {
  21:     displayMessage("Connection closed.");
  22:     $('#btn, #name, #msg').attr('disabled', 'disabled');
  23: };
  24:  
  25: $('#btn').click(function (e) {
  26:     e.preventDefault();
  27:     myWebSocket.send(JSON.stringify({
  28:         name: $('#name').val(),
  29:         msg: $('#msg').val()
  30:     }));
  31:     $('#msg').val('')
  32: });

Not bad right Smile

One thing to note is the way I create the WebSocket object:

   1: var WebSocket = WebSocket || MozWebSocket;
   2: var myWebSocket = new WebSocket("ws://localhost:8181");

I am using the expression WebSocket || MozWebSocket because support for WebSockets is still very experimental and FireFox still uses the Moz prefix. See CanIUse.com for more details about browser support.

 


The server part.

With Server-Sent Events the server part was easy and standard web stuff because we are just using HTTP. With WebSockets this is no longer the case as we are using a socket style connection using the WS scheme. So we need some extra support on the server. As I am doing .NET I want a .NET 4 solution on the server, there are several other non .NET solutions as well. If we search NuGet we see there are thee different WebSocket packages. One is part of WCF 4.5 and an other, SignalR.WebSockets, that is build on top of it. Now SignalR is an awesome product but as this requires .NET 4.5 and this isn’t released yet I am going with the third option, Fleck, which does run on .NET 4 as is.

Fleck is pretty easy to use, just new up an WebSocketServer with the URL to start listening and it has pretty much the same interface as the WebSocket on the client. Whenever a client connects the OnOpen is called and when a message is received the OnMessage callback fires. My ASP.NET MVC home controller looks like this:

   1: public class HomeController : Controller
   2: {
   3:     private static List<IWebSocketConnection> allSockets = new List<IWebSocketConnection>();
   4:  
   5:     static HomeController()
   6:     {
   7:         var server = new WebSocketServer("ws://localhost:8181");
   8:         server.Start(socket =>
   9:         {
  10:             socket.OnOpen = () =>
  11:             {
  12:                 allSockets.Add(socket);
  13:             };
  14:             socket.OnClose = () =>
  15:             {
  16:                 allSockets.Remove(socket);
  17:             };
  18:  
  19:             socket.OnMessage = message =>
  20:             {
  21:                 allSockets.ToList().ForEach(s => s.Send(message));
  22:             };
  23:         });
  24:     }
  25:  
  26:     public ActionResult Index()
  27:     {
  28:         return View();
  29:     }
  30: }

Again pretty simple to use Smile

 

Of course real life isn’t quite as simple as this demo. For one you are now using a direct connection between the browser and one of your servers so any form of load balancing is out of the question here. And as this is real new its quite likely that you will run into routers, proxy severs or the like that don’t support WebSockets. If you really need this functionality now looking at a package as SignalR which makes all of this a lot more reliable makes sense. And the standard SignalR package will work just fine on existing .NET 4 Smile


Enjoy!

www.TheProblemSolver.nl
www.dotnetevents.nl

Posted by Maurice | 1 comment(s)

In deze podcast spreekt Maurice de Beijer met Jurgen Thysmans van Nokia over wat de omschakeling van Nokia naar het Windows Phone 7 platform allemaal voor gevolgen gaat hebben. Tevens bezoeken we het Testpanel Nokia Lumia 800 dat die avond door Tweakers en Nokia samen georganiseerd werd en waar 40 testers met een Nokia Lumia 800 naar huis gingen.

Links:

 

http://www.dotned.nl/PodCasts.aspx?id=18

 

Enjoy!

www.TheProblemSolver.nl
www.dotnetevents.nl

Posted by Maurice | 1 comment(s)
Filed under: , , , ,

In the previous blog post I demonstrated how to use Modernizr to test for the availability of HTML 5 features. Doing so was quite easy but as every test is always performed to add CSS classes to the <html> element there is a bit of overhead in using the default Modernizr JavaScript file. Fortunately they have made a fix for this rather easy and added a page where you can quickly create a custom version with just the checks you need for your site.

 

 

Adding custom checks

The careful reader might have noticed that there is no option for Server-Sent Events I used in the previous blog post. And worse if you take the standard Modernizr JavaScript and use that the test I was using, either the JavaScript or the CSS styles

   1: if (Modernizr.eventsource) {
   2:     // Good to go
   3: }
   4: else {
   5:     // Oops
   6: }

doesn’t work and the JavaScript actually causes an error. The reason the code worked for me is another nice Modernizr capability of adding custom checks. In the Razor master page I added the following custom check using Modernizr.addTest().

   1: <script src="@Url.Content("~/Scripts/modernizr-2.0.6-development-only.js")" type="text/javascript"></script>
   1:  
   2: <script>
   3:     Modernizr.addTest('eventsource', function () { return !!window.EventSource; });
</script>

Adding a test this way automatically adds both the test itself and the extra CSS classes to the <html> element.

 

Adding custom scripts

Another nice capability of Modernizr, actually implemented using yepNope.js, is the capability to conditionally load extra scripts. A great way to load HTML 5 polyfills for missing pieces in specific browsers.

An example, taken from the Modernizr, loading a geo location polyfill for those browser that don’t support geo location out of the box.

   1: Modernizr.load({
   2:   test: Modernizr.geolocation,
   3:   yep : 'geo.js',
   4:   nope: 'geo-polyfill.js'
   5: });

 

Modernizr is a must have in your HTML 5 arsenal.

 

Enjoy!

www.TheProblemSolver.nl
www.dotnetevents.nl

Posted by Maurice | with no comments

Yesterday I blogged about using the new Server-Sent Events or the EventSource object to send messages from the server to the client. But what happens if I try to do this in a browser that doesn’t support Server-Sent Events?

If I run the code from yesterday in Internet Explorer 9 I sill see the following error dialog:

image

The reason is that IE 9 doesn’t support Server-Sent Events, see CanIUse.com, so it results in an Microsoft JScript runtime error: 'EventSource' is undefined exception

HTML5 Feature detection

In the old days if web development we used to check the browser the client was using and make decisions based on the bowser type and version. These days that is no linger a recommended approach as browsers are updated frequently and keeping up to date base on browser versions would be a nightmare.

A better approach, and much more common these days.. is feature detection. Feature detection basically checks if a specific feature is available in a given browser. And because that uses tests based on the official API it is much easier to maintain and more reliable as it doesn’t depend on specific browsers.

In the case of the Server-Sent Events we can check for the existence of the EventSource object using the following test:

   1: if (window.EventSource) {
   2:     // Good to go
   3: }
   4: else {
   5:     // Oops
   6: }

This would work just fine but it means we have to create checks and make sure these work in every browser.

Modernizr to the rescue

Fortunately we don’t have to do so ourselves but we can use the excellent Modernizr JavaScript library. Modernizr contains checks for almost all HTML 5 you might want to test for and will make sure the tests are checked against all relevant browsers. And to make live easy for the ASP.NET MVC developers the team decided to add Modernizr to the standard HTML5 project template so you get it automatically. If you don’t have it yet it is easy to add to an existing project through the NuGet package.

 

The developers solution

Developer write code for their day to day business so as a developer when I have a problem I am going to write some code to solve this problem. By adding Modernizr to the mix and adding a simple check we can use the following code and get the result below.

   1: if (Modernizr.eventsource) {
   2:     var source = new EventSource('home/events');
   3:  
   4:     source.onmessage = function (e) {
   5:         $('<li>').text(e.data).appendTo('#messages');
   6:     };
   7:  
   8:     source.addEventListener('ping', function (e) {
   9:         $('<li>').text(e.data).appendTo('#messages');
  10:         console.log(e.data);
  11:     }, false);
  12: }
  13: else {
  14:     $("<li>This browser doesn't support Server-Sent Events</li>").css('color', 'red').appendTo('#messages');
  15: }

image

Not bad but we can do even better Smile

 

Besides the Modernizr object where we can check of features the library actually adds or removes CSS classes to the root <html> we can use to style element. When a feature exists it adds a class with the same name as the feature, eventsource in this case, if it doesn’t it add as class no-eventsource instead. Using this we can actually start showing or hiding elements using just CSS and no JavaScript code.

Suppose I use the following HTML:

   1: <style>
   2:     html.eventsource .warning
   3:     {
   4:         visibility: hidden;
   5:     }
   6:     html.no-eventsource .warning
   7:     {
   8:         background-color: Red;
   9:     }
  10:     html.no-eventsource #messages
  11:     {
  12:         visibility: hidden;
  13:     }
  14: </style>
  15: <div class='warning'>
  16:     This browser doesn't support Server-Sent Events</div>
  17: <ol id='messages'>
  18: </ol>

We get the following result:

image

You can even test for JavaScript being enabled this way. If it is Modernizr will remove a no-js class in the <html> element and add a js class. Of course if JavaScript is disabled Modernizr can’t add a css class to you must add the no-js class yourself.

The general recommendation for JavaScript is to add it at the bottom of the page, after all content but these CSS classes are the reason you should make an exception for Modernizr and always add that to the <head> of your page.

 

When doing HTML 5 work you just have to live Modernizr Smile

 

Enjoy!

www.TheProblemSolver.nl
www.dotnetevents.nl

Posted by Maurice | 2 comment(s)

There are a lot of cool new features and one of these is Server-Sent Events. According to CanIUse.com Server-Sent Events are usable on almost half of the modern browsers. And as is often the case Internet Explorer is the big missing piece again. But fortunately there are some nice polyfills to take care of IE. More about that some other time.

 

So what are Server-Sent Events?

Server-Sent Events are a way of sending data from the server to the client. There is actually another part of HTML5 that will let you do so and that is the WebSockets standard. The difference between Server-Sent Events and WebSockets is that WebSockets is a 2 directional protocol making it more complex where Server-Sent Events just allow the server to push to the client and it uses HTTP as the underlying transport.

Starting listening for push events on the client is simple, just create a new EventSource object specifying the URL to check for events. Whenever an event is pushed the EventSource.onmessage callback will be called.

 

   1: var source = new EventSource('home/events');
   2:  
   3: source.onmessage = function (e) {
   4:     $('<li>').text(e.data).appendTo('#messages');
   5: };

 


Alternatively you can use the source.addEventListener('message', function (e) {}, false); way of binding an event listener.

Pushing data from the client is also quite easy. In this case I am using an ASP.NET MCV controller to check for messages in a BlockingCollection<string> and is anything is found I return it.

 

   1: public ActionResult Events()
   2: {
   3:     var data = "";
   4:     var sb = new StringBuilder();
   5:     if (_data.TryTake(out data, TimeSpan.FromSeconds(15)))
   6:     {
   7:         sb.AppendFormat("data: {0}: {1}\n\n", DateTime.Now, data);
   8:     }
   9:     return this.Content(sb.ToString(), "text/event-stream");
  10: }

 

The important parts here is that the data is pushed using a MIME type of text/event-stream and the actual data send is prefixed with data:. You can add multiple lines to the data if you want, the message ends with \n\n and if you like you can actually include multiple messages in one go. The data is always send as a string but it you want to provide a richer data type all you need to do is send it as JSON and in your JavaScript code use JSON.parse(e.data) to recreate the original object.

 

Custom events

By default all events are send to the onmessage callback at the client. But if you want to differentiate between different event types you can include the event: eventName syntax in the message send and bind an event listener to the eventName to receive the data. In the following example I am sending actual data using the standard message but if there is no data I send a ping message.

   1: public ActionResult Events()
   2: {
   3:     var data = "";
   4:     var sb = new StringBuilder();
   5:     if (_data.TryTake(out data, TimeSpan.FromSeconds(15)))
   6:     {
   7:         sb.AppendFormat("data: {0}: {1}\n\n", DateTime.Now, data);
   8:     }
   9:     else
  10:     {
  11:         sb.AppendLine("event: ping");
  12:         sb.AppendFormat("data: {0}\n\n", DateTime.Now, data);
  13:     }
  14:     return this.Content(sb.ToString(), "text/event-stream");
  15: }

The client page looks like this:

image

 

   1: <!DOCTYPE html>
   2: <html>
   3: <head>
   4:     <meta charset="utf-8" />
   5:     <title>Server-Sent Events</title>
   6:     <link href="/Content/Site.css" rel="stylesheet" type="text/css" />
   7:     <script src="/Scripts/modernizr-1.7.min.js" type="text/javascript"></script>
   1:  
   2: </head>
   3: <body>
   4:     <div class="page">
   5:         <header>
   6:             <div id="title">
   7:                 <h1>My MVC Application</h1>
   8:             </div>
   9:             <div id="logindisplay">
  10:                     [ <a href="/Account/LogOn">Log On</a> ]
  11:             </div>
  12:             <nav>
  13:                 <ul id="menu">
  14:                     <li><a href="/">Home</a></li>
  15:                     <li><a href="/Home/About">About</a></li>
  16:                 </ul>
  17:             </nav>
  18:         </header>
  19:         <section id="main">
  20:             <ol id='messages'>
  21:             </ol>
  22:         </section>
  23:     </div>
  24:     <script src="../../Scripts/jquery-1.5.1.js" type="text/javascript">
   1: </script>
   2:     <script>
   3:         var source = new EventSource('home/events');
   4:         source.onmessage = function (e) {
   5:             $('<li>').text(e.data).appendTo('#messages');
   6:         };
   7:  
   8:         source.addEventListener('ping', function (e) {
   9:             $('<li>').text(e.data).appendTo('#messages');
  10:         }, false);
  11:     
</script>
   8: </body>
   9: </html>
  10:  


Enjoy!

 

www.TheProblemSolver.nl
www.dotnetevents.nl

Posted by Maurice | 2 comment(s)
Filed under: , , ,

One of the cool new features in HTML5 is Geolocation or the capability to determine where someone is. It turns out most modern browsers support the Geolocation API as you can see on CanIUse.com. Unfortunately Internet Explorer 8, the most popular version of IE at this moment, is the big exception.

The Geolocation API is very easy to use. The basic function to use is the getCurrentPosition() which is located on the geolocation object which in turn is located on the navigator object. It takes a callback for success that give you the location and a failure callback with a reason the location request failed.

 

   1: $(function () {
   2:     if (Modernizr.geolocation) {
   3:         navigator.geolocation.getCurrentPosition(function (e) {
   4:             var coord = e.coords;
   5:             alert(coord);
   6:         }, function(e) {
   7:             alert(e.message);
   8:         });
   9:     }
  10:     else {
  11:         $('<h1>').text('GeoLocation not supported').appendTo('#location');
  12:     }
  13: });

 

I am using jQuery hear to execute the code when the page is loaded. I am also using Modernizr to check is the current browser supports the Geolocation API. Using Modernizr is highly recommended when you start working with HTML5 style features and need to check if the current browser supports a particular feature.

Of course just altering the user with his or her location is not very useful so lets show a map instead. Doing just that with Google maps is real easy. First make sure you load the required JavaScript API from http://maps.googleapis.com/maps/api/js?sensor=false and you can new up a Map and a  LatLng object for the position and display it on the web page.

 

   1: <!DOCTYPE html>
   2: <html xmlns="http://www.w3.org/1999/xhtml">
   3: <head>
   4:     <title>Geo Location</title>
   5:     <link href="../Content/Site.css" rel="stylesheet" type="text/css" />
   6:     <script src="../Scripts/modernizr-2.0.6-development-only.js"></script>
   1:  
   2: </head>
   3: <body>
   4:     <div id="location" class='full-screen'>
   5:     </div>
   6:     <script src="../Scripts/jquery-1.6.4.js">
   1: </script>
   2:     <script src="http://maps.googleapis.com/maps/api/js?sensor=false">
   3:     
</script>
   1:  
   2:     <script>
   3:         $(function () {
   4:             if (Modernizr.geolocation) {
   5:                 navigator.geolocation.getCurrentPosition(function (e) {
   6:                     var position = new google.maps.LatLng(e.coords.latitude, e.coords.longitude);
   7:                     var map = new google.maps.Map($('#location').get(0), {
   8:                         zoom: 15,
   9:                         center: position,
  10:                         mapTypeId: google.maps.MapTypeId.ROADMAP
  11:                     });
  12:                     new google.maps.Marker({
  13:                         position: position,
  14:                         map: map,
  15:                         title: 'Accurate to within ' + e.coords.accuracy + ' meters.'
  16:                     });
  17:                 });
  18:             }
  19:             else {
  20:                 $('<h1>').text('GeoLocation not supported').appendTo('#location');
  21:             }
  22:         });
  23:     
</script>
   7: </body>
   8: </html>

This is the complete page to render following map of my location.

 

image

 

So how accurate is it?

That really depends. On my laptop I am getting a position to with 100 meters of where I am, the location returned actually claims to be accurate to 87 meters. My laptop doesn’t have a GPS but I am using Wi-Fi and that results in a pretty decent location. On my phone the position is a lot better because it can actually use the GPS is needed. But on my desktop, connected through cables instead of Wi-Fi, the position is several kilometers of. So it very much depends on the device.

 

But my privacy

Fortunately your privacy is save. Before a browser returns your location it needs to get your permission. So no need to be afraid of websites trying to sniff your location without asking your permission first.

 

Enjoy!

 

www.TheProblemSolver.nl
www.dotnetevents.nl

Posted by Maurice | with no comments
Filed under: , ,

For those who missed the online event about building JavaScript and HTML5 client for a REST service build using the new WCF Web API the recordings are up. You can download the hi res recording here or download one of the other formats from the main page here. And remember there a bunch of other useful recording from other DevelopMentor instructors on the same page.

 

Enjoy!

 

www.TheProblemSolver.nl
www.dotnetevents.nl

Posted by Maurice | 2 comment(s)
Filed under: , , , , ,