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

In a previous post I showed how to unit test an ASP.NET WebAPI Controller. But with a REST service there is both a client and a service component. Assuming for a moment the client part is also written in C# we should test that as well.

In this case the client application contains the following class to load books from the REST WebAPI controller:

   1: public class BooksClient
   2: {
   3:     private readonly HttpClient _httpClient;
   4:  
   5:     public BooksClient(HttpClient httpClient)
   6:     {
   7:         _httpClient = httpClient;
   8:         BaseUrl = new Uri("http://localhost:63895/api/books/");
   9:     }
  10:  
  11:     public Uri BaseUrl { get; private set; }
  12:  
  13:     public IEnumerable<Book> GetBooks()
  14:     {
  15:         var response = _httpClient.GetAsync(BaseUrl).Result;
  16:         response.EnsureSuccessStatusCode();
  17:         return response.Content.ReadAsAsync<Book[]>().Result;
  18:     }
  19:  
  20:     public Book GetBook(int id)
  21:     {
  22:         var requestUri = new Uri(BaseUrl, id.ToString(CultureInfo.InvariantCulture));
  23:         var response = _httpClient.GetAsync(requestUri).Result;
  24:         response.EnsureSuccessStatusCode();
  25:         return response.Content.ReadAsAsync<Book>().Result;
  26:     }
  27:  
  28:     public Tuple<Book, Uri> PostBook(Book book)
  29:     {
  30:         var response = _httpClient.PostAsJsonAsync(BaseUrl.ToString(), book).Result;
  31:         response.EnsureSuccessStatusCode();
  32:         var newBook = response.Content.ReadAsAsync<Book>().Result;
  33:         var location = response.Headers.Location;
  34:         return new Tuple<Book, Uri>(newBook, location);
  35:     }
  36: }

This class uses the HttpClient to request the data from the service and extracts the books from the body before returning them.

 

Testing the BooksClient class

If we want to test this class we need to pass in an HttpClient object. This might not sound like a big deal but as this class doesn’t implement an interface we can’t use most of the standard mocking frameworks like Moq to replace the HttpClient with a test fake.

It turns out that this isn’t a big issue though as you can replace the internal pipeline of the HttpClient instead. This is done by passing in an HttpMessageHandler. This HttpMessageHandler is used as the pipeline to send requests and we can completely replace this with our own implementation. The easiest way is by creating a dummy DelegatingHandler and overriding the SendAsync() function to just return a fake response instead of actually doing an HTTP request.

 

The TestingDelegatingHandler<T> class

Creating a dummy DelegatingHandler  isn’t hard but using the TestingDelegatingHandler<T> makes this really easy. The complete code is below and is pretty simple:

   1: public class TestingDelegatingHandler<T> : DelegatingHandler
   2: {
   3:     private Func<HttpRequestMessage, HttpResponseMessage> _httpResponseMessageFunc;
   4:  
   5:     public TestingDelegatingHandler(T value)
   6:         : this(HttpStatusCode.OK, value)
   7:     { }
   8:  
   9:     public TestingDelegatingHandler(HttpStatusCode statusCode)
  10:         : this(statusCode, default(T))
  11:     { }
  12:  
  13:     public TestingDelegatingHandler(HttpStatusCode statusCode, T value)
  14:     {
  15:         _httpResponseMessageFunc = request => request.CreateResponse(statusCode, value);
  16:     }
  17:  
  18:     public TestingDelegatingHandler(
  19:         Func<HttpRequestMessage, HttpResponseMessage> httpResponseMessageFunc)
  20:     {
  21:         _httpResponseMessageFunc = httpResponseMessageFunc;
  22:     }
  23:  
  24:     protected override Task<HttpResponseMessage> SendAsync(
  25:         HttpRequestMessage request, CancellationToken cancellationToken)
  26:     {
  27:         return Task.Factory.StartNew(() => _httpResponseMessageFunc(request));
  28:     }
  29: }

The most important function is the SendAsync() which returns a new Task. Did I mention that the WebAPI is completely async enabled? Well it is so we just have to return a new Task that returns the HttpResponseMessage instead of the HttpResponseMessage directly.


Testing the GetBooks() function

The GetBooks() function gets all books from the REST service. A test is pretty simple. The only thing to be aware of is that in order to use the TestingDelegatingHandler we also need to create an HttpServer object and pass in an HttpConfiguration object. Normally an empty HttpConfiguration will be enough.

   1: [TestMethod]
   2: public void WhenGettingAllBooksTheyShouldBeReturned()
   3: {
   4:     // Arrange
   5:     var books = new[]
   6:     {
   7:         new Book{Id = 1, Author = "Me", Title = "Book 1"},
   8:         new Book{Id = 2, Author = "You", Title = "Book 2"}
   9:     };
  10:     var testingHandler = new TestingDelegatingHandler<Book[]>(books);
  11:     var server = new HttpServer(new HttpConfiguration(), testingHandler);
  12:     var client = new BooksClient(new HttpClient(server));
  13:  
  14:     // Act
  15:     var booksReturned = client.GetBooks();
  16:  
  17:     // Assert
  18:     Assert.AreEqual(2, booksReturned.Count());
  19: }


Simple enough right?

 

Testing the GetBook(int id) function

Testing this method is not much harder but we need to test both a positive and a negative result. The positive is just as simple as above:

   1: [TestMethod]
   2: public void WhenGettingAValidBookItShouldBeReturned()
   3: {
   4:     // Arrange
   5:     var book = new Book { Id = 2, Author = "You", Title = "Book 2" };
   6:     var testingHandler = new TestingDelegatingHandler<Book>(book);
   7:     var server = new HttpServer(new HttpConfiguration(), testingHandler);
   8:     var client = new BooksClient(new HttpClient(server));
   9:  
  10:     // Act
  11:     var bookReturned = client.GetBook(2);
  12:  
  13:     // Assert
  14:     Assert.IsNotNull(bookReturned);
  15:     Assert.AreEqual("Book 2", bookReturned.Title);
  16: }

 

The negative case isn’t much harder, all we need to do is make sure our dummy service returns an HTTP 404 Not Found status. With the overloads for the TestingDelegatingHandler<T> this is easy enough. See below:

   1: [TestMethod]
   2: [ExpectedException(typeof(HttpRequestException))]
   3: public void WhenGettingAnInvalidBookItShouldThrow()
   4: {
   5:     // Arrange
   6:     var testingHandler = new TestingDelegatingHandler<Book>(HttpStatusCode.NotFound);
   7:     var server = new HttpServer(new HttpConfiguration(), testingHandler);
   8:     var client = new BooksClient(new HttpClient(server));
   9:  
  10:     // Act
  11:     client.GetBook(-1);
  12:  
  13:     // Assert
  14:     Assert.Fail();
  15: }

 

Nice and simple right?

 

Testing am HTTP POST action

Testing an HTTP POST action to add a new book is slightly more complex. Not a whole lot but the REST convention is to return both an HTTP 201 Created status as well as the location of the new resource in an HTTP header. For this purpose the TestingDelegatingHandler<T> has an overload where you can just pass in a lambda to create the response. This gives us full flexibility and with that the test is simple enough.

   1: [TestMethod]
   2: public void WhenPostingABookItShouldBeAdded()
   3: {
   4:     // Arrange
   5:     var book = new Book { Id = 2, Author = "You", Title = "Book 2" };
   6:     var testingHandler = new TestingDelegatingHandler<Book>(request =>
   7:     {
   8:         var response = request.CreateResponse(HttpStatusCode.Created, book);
   9:         response.Headers.Location =
  10:             new Uri(string.Format("http://domain.com/api/books/{0}", book.Id));
  11:         return response;
  12:     });
  13:     var server = new HttpServer(new HttpConfiguration(), testingHandler);
  14:     var client = new BooksClient(new HttpClient(server));
  15:  
  16:     // Act
  17:     var result = client.PostBook(new Book());
  18:  
  19:     // Assert
  20:     var bookReturned = result.Item1;
  21:     Assert.IsNotNull(bookReturned);
  22:     Assert.AreEqual("Book 2", bookReturned.Title);
  23:  
  24:     var location = result.Item2;
  25:     Assert.AreEqual(new Uri("http://domain.com/api/books/2"), location);
  26: }

 

Of course we still need tests for updating existing resources as well as deleting them but with these examples those should be easy enough :-)

 

Enjoy!

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

 

Index:

  1. Getting started with AngularJS
  2. Creating an AngularJS Controller
  3. The AngularJS $scope is not the MVC Model
  4. Using repeating elements in AngularJS
  5. Filtering the data in an AngularJS ngRepeat element

 

Showing a list of items like in the previous post is nice but if the list is large most users appreciate the possibility to search in it. Turns out that AngularJS has that already build in so it is really simple to do.

 

We are using exactly the same controller as before, all it contains is a list of people.

   1: function DemoCtrl($scope) {
   2:  
   3:     $scope.people = [
   4:         { firstName: 'Maurice', lastName: 'de Beijer' },
   5:         { firstName: 'Jacob', lastName: 'Smith' },
   6:         { firstName: 'Sophia', lastName: 'Brown' },
   7:         { firstName: 'Mason', lastName: 'Lee' },
   8:         { firstName: 'Emma', lastName: 'Wilson' },
   9:         { firstName: 'Ethan', lastName: 'Martin' },
  10:         { firstName: 'Emily', lastName: 'Taylor' },
  11:         { firstName: 'Wiliam', lastName: 'Wong' },
  12:         { firstName: 'Emily', lastName: 'Campbell' },
  13:         { firstName: 'Liam', lastName: 'Williams' }
  14:     ];
  15: }

 

To let the use filter the list we are going to add the AngularJS filter directive.

image

The change to the markup is minimal. I did change the items to be an ordered list but that is not important. The important part is adding the “| filter:filterText” to the ng-repeat directive. This filters the data in the array to containing the text in the filterText property. And the filter text is the result of the input element I added and data bound using the ng-model directive.

 

   1: <!DOCTYPE html>
   2: <html lang="en">
   3: <head>
   4:     <title>AngularJS Demo</title>
   5:     <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
   6: </head>
   7: <body ng-app ng-controller="DemoCtrl">
   8:     Search:
   9:     <input type="text" ng-model="filterText" autofocus />
  10:  
  11:     <ol>
  12:         <li ng-repeat="person in people | filter:filterText">
  13:             {{person.firstName}} {{person.lastName}}
  14:         </li>
  15:     </ol>
  16:  
  17:     <script src="Scripts/angular.js"></script>
   1:  
   2:     <script src="App/Controllers/DemoCtrl.js">
</script>
  18: </body>
  19: </html>

 

Nice and simple, just the way I like it :-)

Posted by Maurice | 1 comment(s)

One of he goals of the ASP.NET WebAPI is to make REST style API controllers more testable than more traditional WCF services where in the past. For the most part that is true but there are cases where an ApiController depends on the actual incoming request and its data and things can become a bit more difficult.

Testing a simple ApiController that gets data

Suppose we have the following ASP.NET WebAPI Controller with two Get methods, the first returns the complete list of books and the second returns the book with the requested ID.

 

   1: public class BooksController : ApiController
   2: {
   3:     private readonly IBooksRepository _repo;
   4:  
   5:     public BooksController()
   6:         : this(new BooksRepository())
   7:     {
   8:  
   9:     }
  10:     public BooksController(IBooksRepository repository)
  11:     {
  12:         _repo = repository;
  13:     }
  14:  
  15:     // GET api/books
  16:     public IEnumerable<Book> Get()
  17:     {
  18:         return _repo.GetBooks();
  19:     }
  20:  
  21:     // GET api/books/5
  22:     public HttpResponseMessage Get(int id)
  23:     {
  24:         var book = _repo.GetBook(id);
  25:  
  26:         if (book == null)
  27:         {
  28:             return Request.CreateResponse(HttpStatusCode.NotFound);
  29:         }
  30:  
  31:         return Request.CreateResponse(HttpStatusCode.OK, book);
  32:     }
  33:  
  34:     // Remainder ommitted

 

Testing the Get() method

The Get() method that returns all books is easy enough to test. There are no dependencies on WebAPI bits, all it does is return a enumeration of books.

   1: [TestMethod]
   2: public void WhenGettingItShouldReturnAllBooks()
   3: {
   4:     // Arrange
   5:     var controller = new BooksController();
   6:  
   7:     // Act
   8:     var books = controller.Get();
   9:  
  10:     // Assert
  11:     Assert.AreEqual(5, books.Count());
  12: }

 

No big deal there :-)

 

Testing the Get(id) method

When getting a specific book things are a bit more complex. The requested Id might not exist and in that case we should return a specific HTTP response status code of 404 NotFound. This results in that the ApiController method uses the Request property to create a new HttpResponseMessage with the specific HTTP status code. If we just call this method we will receive an ArgumentNullException in the CreateResponse() function.

System.ArgumentNullException: Value cannot be null.
Parameter name: request

Just setting the Request property to a new instance of HttpRequestMessage is a start but not quite enough. With just this change you will see an InvalidOperationException with the following message:

System.InvalidOperationException: The request does not have an associated configuration object or the provided configuration was null.

To fix this we need to add a HttpConfiguration object through the Properties dictionary as below:

   1: [TestMethod]
   2: public void WhenGettingWithAKnownIdItShouldReturnThatBook()
   3: {
   4:     // Arrange
   5:     var controller = new BooksController
   6:     {
   7:         Request = new HttpRequestMessage()
   8:         {
   9:             Properties = { { HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration() } }
  10:         }
  11:     };
  12:  
  13:     // Act
  14:     var response = controller.Get(1);
  15:  
  16:     // Assert
  17:     Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
  18:     var book = response.Content.ReadAsAsync<Book>().Result;
  19:     Assert.AreEqual(1, book.Id);
  20: }

 

Testing for getting with an invalid ID is equally simple:

   1: [TestMethod]
   2: public void WhenGettingWithAnUnknownIdItShouldReturnNotFound()
   3: {
   4:     // Arrange
   5:     var controller = new BooksController()
   6:     {
   7:         Request = new HttpRequestMessage()
   8:         {
   9:             Properties = { { HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration() } }
  10:         }
  11:     };
  12:  
  13:     // Act
  14:     var response = controller.Get(999);
  15:  
  16:     // Assert
  17:     Assert.AreEqual(HttpStatusCode.NotFound, response.StatusCode);
  18: }


Testing an HTTP PUT operation

Testing an update using an HTTP put is just as simple as a testing a get action. The implementation looks like this:

   1: // PUT api/books/5
   2: public HttpResponseMessage Put(int id, Book book)
   3: {
   4:     if (!ModelState.IsValid)
   5:     {
   6:         return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
   7:     }
   8:  
   9:     var newBook = _repo.UpdateBook(book);
  10:     return Request.CreateResponse(HttpStatusCode.OK, newBook);
  11: }

And the related test goes as follows:

   1: [TestMethod]
   2: public void WhenPuttingABookItShouldBeUpdated()
   3: {
   4:     // Arrange
   5:     var controller = new BooksController()
   6:     {
   7:         Request = new HttpRequestMessage()
   8:         {
   9:             Properties = { { HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration() } }
  10:         }
  11:     };
  12:  
  13:     // Act
  14:     var book = new Book() {Id = 1, Title = "New Title", Author = "New Author"};
  15:     var response = controller.Put(book.Id, book);
  16:  
  17:     // Assert
  18:     Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
  19:     var newBook = response.Content.ReadAsAsync<Book>().Result;
  20:     Assert.AreEqual(1, newBook.Id);
  21:     Assert.AreEqual("New Title", newBook.Title);
  22:     Assert.AreEqual("New Author", newBook.Author);
  23: }


No big surprises there :-)

 

Adding new data using an HTTP POST action

Testing an HTTP POST used to add a new book is a little, but not much more, involved. The main reason for this is the HTTP convention to return a 201 Created status code and to include the HTTP Location header with an URI where the new resource can be found. The implementation is as follows:

   1: // POST api/books
   2: public HttpResponseMessage Post(Book book)
   3: {
   4:     if (!ModelState.IsValid)
   5:     {
   6:         return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
   7:     }
   8:  
   9:     var newBook = _repo.AddBook(book);
  10:  
  11:     var response = Request.CreateResponse(HttpStatusCode.Created, newBook);
  12:  
  13:     var uriString = Url.Link("DefaultApi", new { id = newBook.Id }) ?? string.Empty;
  14:     response.Headers.Location = new Uri(uriString);
  15:  
  16:     return response;
  17: }

 

If we try to test this with a similar setup action as the previous tests we will see a KeyNotFoundException below:

System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.

Not a very helpful message, what key is not found? The stack trace gives a clue and it turns out we need to configure the HTTP routing on the HttpConfiguration object. Easy enough as just calling WebApiConfig.Register() with the configuration should do the trick.

However this just leads us to an UriFormatException as the Uri.Link() function returns null.

It turns out we also need to add the HttpRouteData to the Request Properties dictionary with the controller name. No big deal but not exactly obvious.

The correct unit test is as follows:

   1: [TestMethod]
   2: public void WhenPostingANewBookShouldBeAdded()
   3: {
   4:     // Arrange
   5:     var httpConfiguration = new HttpConfiguration();
   6:     WebApiConfig.Register(httpConfiguration);
   7:     var httpRouteData = new HttpRouteData(httpConfiguration.Routes["DefaultApi"], 
   8:         new HttpRouteValueDictionary { { "controller", "Books" } });
   9:     var controller = new BooksController()
  10:     {
  11:         Request = new HttpRequestMessage(HttpMethod.Post, "http://domain.com/api/books/")
  12:         {
  13:             Properties = 
  14:             {
  15:                 { HttpPropertyKeys.HttpConfigurationKey, httpConfiguration },
  16:                 { HttpPropertyKeys.HttpRouteDataKey, httpRouteData } 
  17:             }
  18:         }
  19:     };
  20:  
  21:     // Act
  22:     var response = controller.Post(new Book()
  23:     {
  24:         Title = "A new book",
  25:         Author = "The author"
  26:     });
  27:  
  28:     // Assert
  29:     Assert.AreEqual(HttpStatusCode.Created, response.StatusCode);
  30:     var addedBook = response.Content.ReadAsAsync<Book>().Result;
  31:  
  32:     Assert.AreEqual(string.Format("http://domain.com/api/Books/{0}", 
  33:         addedBook.Id), response.Headers.Location.ToString());
  34: }

 

The arrange section might be a bit more verbose but once you know what to add no big deal.

 

Enjoy :-)

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

 

Index:

  1. Getting started with AngularJS
  2. Creating an AngularJS Controller
  3. The AngularJS $scope is not the MVC Model
  4. Using repeating elements in AngularJS
  5. Filtering the data in an AngularJS ngRepeat element

 

In the previous  posts I showed how to get started with AngularJS and use some of the basic AngularJS directives to data bind. In these examples I uses a really simple single element to bind to. However in lots of business cases you really need to display a list of repeating elements. Fortunately this is really easy to do.

 

The AngularJS ng-repeat directive

Whenever you need to repeat a specific block of HTML markup for each item in an array the ng-repeat directive is your friend. Take a look at the simple list of people below.

image

 

The data for this list is contained in an array that is added to the $scope object in the controller. The actual controller is real simple, see the code below.

 

   1: function DemoCtrl($scope) {
   2:  
   3:     $scope.people = [
   4:         { firstName: 'Maurice', lastName: 'de Beijer' },
   5:         { firstName: 'Jacob', lastName: 'Smith' },
   6:         { firstName: 'Sophia', lastName: 'Brown' },
   7:         { firstName: 'Mason', lastName: 'Lee' },
   8:         { firstName: 'Emma', lastName: 'Wilson' },
   9:         { firstName: 'Ethan', lastName: 'Martin' },
  10:         { firstName: 'Emily', lastName: 'Taylor' },
  11:         { firstName: 'Wiliam', lastName: 'Wong' },
  12:         { firstName: 'Emily', lastName: 'Campbell' },
  13:         { firstName: 'Liam', lastName: 'Williams' }
  14:     ];
  15: }

 

The markup to generate the list in the screenshot is also real simple:

 

   1: <!DOCTYPE html>
   2: <html lang="en">
   3: <head>
   4:     <title>AngularJS Demo</title>
   5:     <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
   6: </head>
   7: <body ng-app ng-controller="DemoCtrl">
   8:     <div ng-repeat="person in people">
   9:         {{person.firstName}} {{person.lastName}}
  10:     </div>
  11:  
  12:     <script src="Scripts/angular.js"></script>
   1:  
   2:     <script src="App/Controllers/DemoCtrl.js">
</script>
  13: </body>
  14: </html>

 

The DIV element containing the ng-repeat, and everything inside it, is simply repeated for every person in the array of people. Simple right :-)

 

Editing the people

Editing the people in the list is really easy, just add an input control and use the same ng-model directive as before.

   1: <!DOCTYPE html>
   2: <html lang="en">
   3: <head>
   4:     <title>AngularJS Demo</title>
   5:     <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
   6: </head>
   7: <body ng-app ng-controller="DemoCtrl">
   8:     <div ng-repeat="person in people">
   9:         <input type="text" ng-model="person.firstName"/>
  10:         {{person.firstName}} {{person.lastName}}
  11:     </div>
  12:  
  13:     <script src="Scripts/angular.js"></script>
   1:  
   2:     <script src="App/Controllers/DemoCtrl.js">
</script>
  14: </body>
  15: </html>

 

In the screenshot below I am changing Jacob to Bob and as I type in the input element the text behind it is updated immediately.

image

 

Enjoy :-)

Posted by Maurice | with no comments
Filed under: ,

 

Index:

  1. Getting started with AngularJS
  2. Creating an AngularJS Controller
  3. The AngularJS $scope is not the MVC Model
  4. Using repeating elements in AngularJS
  5. Filtering the data in an AngularJS ngRepeat element

 

In the previous post I showed how to create and use an MVC Controller in AngularJS to manage the logic of an application. In this post I showed how to use the $scope variable that is passed into the Controller to share data between the Controller and the View. This may lead you to believe that the $scope is the MVC Model used but you would be completely wrong.

 

The $scope is not the MVC Model

There is a common believe that the $scope object in AngularJS is the MVC Model, or ViewModel, but that is wrong. In fact the $scope is just the glue object that should be used to share things between the controller and the view. Now that sounds awfully like a model but it isn’t. In fact you will see a lot of people do just that and as a result report bugs like this one. In fact this isn’t a bug and it works as designed. The correct way is to add the model as a property to the @scope instead so the controller and the view can share it.

 

So what is the problem with treating the $scope as the Model?

The biggest problem is in the way AngularJS works with it’s scopes. There usually isn’t just a single scope but a collection of nested scopes. And these nested scopes are linked together through the JavaScript prototype chain. This means that as long as you only read properties JavaScript will search up the chain of prototypes. However as soon as you write to what feels the same property you actually create a new one on the scope you are writing to. The net result is you now have two different but identically named properties on different linked scopes. And this means your application might just behave in an unexpected way as with the “bug” mentioned above.

 

The correct way of working with $scope objects

image

It turns out the correct way of working with scope is pretty easy.

Treat $scope as read-only in views

Treat $scope as write-only in controllers

Or an even simpler rule:

An ng-model directive should always contain a “.” so it updates a property on the model which is on the scope and not a property on the scope directly. If you don’t have a “.” in your ng-model you are doing it wrong!

But don’t just take my word for it. Take a good look at this video from Miško Hevery starting at about 0:29. BTW the rest of this video is highly recommended as well.

 

Fixing our calculator controller and view

With this knowledge is it easy to see that the controller and view from the previous post are actually wrong as the view is writing directly to the $scope x and y properties. In fact the only reason this appeared to work is that the example was so simple that no nested scopes where created. Still lets do the proper thing and fix the example.

The corrected view is now:

   1: <!DOCTYPE html>
   2: <html lang="en">
   3: <head>
   4:     <title>AngularJS Demo</title>
   5:     <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
   6: </head>
   7:     <body ng-app ng-controller="DemoCtrl">
   8:         <input type="text" ng-model="model.x"/>
   9:         {{model.operator}}
  10:         <input type="text" ng-model="model.y"/>
  11:         
  12:         <button ng-click="add()">+</button>
  13:         <button ng-click="multiply()">*</button>
  14:         
  15:         = {{model.result}}
  16:  
  17:         <script src="Scripts/angular.js"></script>
   1:  
   2:         <script src="App/Controllers/DemoCtrl.js">
</script>
  18:     </body>
  19: </html>

 

And the corrected controller now is as follows.

   1: function DemoCtrl($scope) {
   2:     $scope.model = {
   3:         x: 2,
   4:         y: 3,
   5:         result : "?",
   6:         operator : "?"
   7:         };
   8:  
   9:     $scope.multiply = function () {
  10:         $scope.model.operator = "*";
  11:         $scope.model.result = (+$scope.model.x) * (+$scope.model.y);
  12:     };
  13:  
  14:     $scope.add = function () {
  15:         $scope.model.operator = "+";
  16:         $scope.model.result = (+$scope.model.x) + (+$scope.model.y);
  17:     };
  18: }

 

Maybe not a big change but important to get right.

 

Enjoy!

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

 

Index:

  1. Getting started with AngularJS
  2. Creating an AngularJS Controller
  3. The AngularJS $scope is not the MVC Model
  4. Using repeating elements in AngularJS
  5. Filtering the data in an AngularJS ngRepeat element

 

In the previous blog post I showed how to get started with a really minimal AngularJS application. Even though the app could multiply two numbers it could hardly be called useful and as it turns out that is about as much as I could do with it.

 

Model View Controller

AngularJS is an MVC framework. So far we have only seen the View part as the HTML used was the view used to render the page to the user. As the name suggest there should be more in the form of a Controller and a Model.

The Controller part of an MVC application is normally the glue that ties a specific part of that application together. It gathers the data (Model) together and tells the View to render the data to the user. It also responds to events to do things.

Suppose we want to expand on the simple page from the previous post and turn this into a simple calculator, like in the screenshot below, the controller would be responsible for the calculations and the view would just be about displaying the data and not, like with the previous example, contain the actual calculation.

image

 

The AngularJS Controller

The controller that drives the logic of the application is a pretty simple JavaScript constructor function. As this is used with the new keyword to create an object I have capitalized the first letter as is the convention in JavaScript.

 

   1: function DemoCtrl($scope) {
   2:     $scope.x = 2;
   3:     $scope.y = 3;
   4:     $scope.result = "?";
   5:     $scope.operator = "?";
   6:     
   7:     $scope.multiply = function() {
   8:         $scope.operator = "*";
   9:         $scope.result = (+$scope.x) * (+$scope.y);
  10:     };
  11:  
  12:     $scope.add = function () {
  13:         $scope.operator = "+";
  14:         $scope.result = (+$scope.x) + (+$scope.y);
  15:     };
  16: }

 

The code basically consists of the X and Y value to be used in the calculation, two functions for adding and multiplying and a way to show the result and operator used. Adding two more functions for divide and subtract should be a simple enough exercise. The code is simple enough and pretty standard JavaScript. For those not used to JavaScript the (+$scope.x) expression is one of the ways you can convert a string to a number in JavaScript.

One special AngularJS thing is the $scope variable passed into the function and used.

 

What is the $scope?

The $scope variable is inserted automatically by AngularJS and serves as the bridge to share data between the controller and the view. Each variable added to the $scope is automatically be available for use in view data binding expressions. In fact there is always a scope, in the example from the previous the values where still stored in an AngularJS scope even though no controller was used.

The way AngularJS knows what to pass to the controller function is determined by the name. Just because we named it $scope AngularJS knows what to pass. This is done by a mechanism called dependency injection which is a very powerful mechanism used to separate different parts of the application and wire them up automatically at runtime while allowing us to pass in dummy services for testing purposes.

 

The AngularJS View

The view used is similar to the example from the previous blog post.

 

   1: <!DOCTYPE html>
   2: <html lang="en">
   3: <head>
   4:     <title>AngularJS Demo</title>
   5:     <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
   6: </head>
   7:     <body ng-app ng-controller="DemoCtrl">
   8:         <input type="text" ng-model="x"/>
   9:         {{operator}}
  10:         <input type="text" ng-model="y"/>
  11:         
  12:         <button ng-click="add()">+</button>
  13:         <button ng-click="multiply()">*</button>
  14:         
  15:         = {{result}}
  16:  
  17:         <script src="Scripts/angular.js"></script>
   1:  
   2:         <script src="App/Controllers/DemoCtrl.js">
</script>
  18:     </body>
  19: </html>

 

New is the ng-controller attribute that tells AngularJS to create the controller and what part of the HTML view it controls. In the view we don’t have to use the $scope variable, every expression is always evaluated scoped to the current $scope.

 

Testing the controller

One of the reasons for using an MVC framework is the capability to test the code. As the controller has no requirements for testing it should be easy enough to test it. Below is a test for adding two numbers using QUnit.

 

   1: test("Test adding 3 + 7", function () {
   2:     // Arrange
   3:     var scope = {};
   4:     var ctrl = new DemoCtrl(scope);
   5:     scope.x = "3";
   6:     scope.y = "7";
   7:  
   8:     // Act
   9:     scope.add();
  10:  
  11:     // Assert
  12:     ok(scope.operator === "+", "The operator should be +");
  13:     ok(scope.result === 10, "3 + 7 should be 10");
  14: });

 

Enjoy!

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

 

 

Index:

  1. Getting started with AngularJS
  2. Creating an AngularJS Controller
  3. The AngularJS $scope is not the MVC Model
  4. Using repeating elements in AngularJS
  5. Filtering the data in an AngularJS ngRepeat element

 

One of the nicer JavaScript frameworks out there to work with must be AngularJS. Now there are quite a few other ones out there and I have used a number of them but AngularJS seems to be the most structured of them. And while it is really powerful it is also really easy to get started with.

AngularJS is a client side framework for creating rich web applications using JavaScript and HTML. It isn’t just a library like jQuery or Knockout.js where you create the structure and call into the library as you see fit. With a framework like AngularJS it is the other way round and it calls into your code. This means you have to like the way it is designed but fortunately AngularJS is pretty flexible so that is not a big penalty to pay. In fact it is more of a benefit as it helps structure your application in a good way.

 

The simplest AngularJS application

Below is pretty much the simplest AngularJS application you can make. Maybe not very functional yet but is shows a few of the very important parts.

 

image

So what does it get to display a “2” on the screen? Well first of all the “2” isn’t a literal but actually a result of adding 1 + 1 together on the client. So this is already a “somewhat” dynamic HTML/JavaScript application. The complete code listing is below.

 

   1: <!DOCTYPE html>
   2: <html lang="en">
   3: <head>
   4:     <title>AngularJS Demo</title>
   5:     <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
   6: </head>
   7:     <body ng-app>
   8:         {{1 + 1}}
   9:         <script src="Scripts/angular.js"></script>
  10:     </body>
  11: </html>

 

There are a few interesting things to note about this.

First of all there is the required script reference to angular.js. Either download this from the AngularJS site or use the NuGet package to add it to your Visual Studio 2012 project. No big new thing here.

Unlike with libraries like jQuery which we load using a similar script tag and then call the jQuery $() function whenever we want to things work a little different with AngularJS. In the case of a framework like AngularJS we let it do it’s work. With AngularJS we need to either do an automatic bootstrap or do so manually. The automatic process is by far the easiest and all we need to add for that is the ng-app attribute to some HTML element. In this case I added it to the <body> element so the whole page is an AngularJS application. If you prefer you can add it to a sub section of the page.

The last interesting part if the {{1 + 1}} part inside the body. The {{}} part is a data binding expression AngularJS will evaluate for us and display the result. In this case we are just adding two numbers but as we will see later we can do far more with this.

 

Making things interactive

The previous example is nice but I could just as well have hardcoded the value “2” in there. So lets make things a bit more interactive and have the user enter two numbers we can multiply.

 

image

The complete code needed for this is not much harder see below.

   1: <!DOCTYPE html>
   2: <html lang="en">
   3: <head>
   4:     <title>AngularJS Demo</title>
   5:     <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
   6: </head>
   7:     <body ng-app>
   8:         <input type="text" ng-model="x"/>
   9:         *
  10:         <input type="text" ng-model="y"/>
  11:         = {{x * y}}
  12:         <script src="Scripts/angular.js"></script>
  13:     </body>
  14: </html>

 

 

The new thing in this example is that we have two <input> controls with an ng-model attribute. These ng-model attributes are used for two way data binding input controls with data used by AngularJS. In the expression below {{x * y}} we multiply the two numbers added. And with this interactive calculator we still had to write no JavaScript, the closest we came to writing code is a single data binding expression in the HTML.

 

Sweet :-)

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

In this podcast Hassan Fadili speaks with Neno Loje (VS ALM MVP) about some of the new features in Visual Studio ALM & Visual Studio Team Foundation Service 2012. Of course, Neno also talks about some of the success stories and other areas that might be interesting to anyone who has a passion for application life cycle management.

Links:

Posted by Maurice | with no comments
Filed under: ,

For a change an English language podcast :-)

 

In this podcast Maurice de Beijer speaks with Mads Kristensen about web tooling in Visual Studio 2012. Besides the standard build in tooling for web developer they also talk about Web Essentials 2012, the plugin Mads develops in his spare time to give web developers even more features and capabilities.

Links:

 

Enjoy!

Posted by Maurice | with no comments
Filed under: ,

I really like SignalR for its capability to do push notifications from the server to the client. But there are a few thing in SignalR I am not quite happy with. Fortunately SignalR is really pluggable and you can change it to suit your needs. :-)

 

PascalCase versus camelCase

One thing I am not really happy about is the fact that all data is send over the wire with a request as is. And with SignalR the server tends to be C# where the convention is to have methods and properties in PascalCase. The client side however is JavaScript where the usual convention is to have methods and properties in camelCase.

 

With functions defined on a SignalR Hub this is no problem. SignalR does the right thing and converts them from the server side PascalCase to the client side camelCase so everyone is happy.

 

However with the data passed as arguments this is not the case and they are passed as is. It turns out SignalR is using JSON.NET which is a really powerful JSON serializer that can do just that. All you need to do is start using the CamelCasePropertyNamesContractResolver and Bob is your uncle. Or is he?

 

Unfortunately things aren’t that simple. It turns out just using CamelCasePropertyNamesContractResolver will break the internal SignalR data contracts and that is not a good thing. But with a bit of help we can still get this to work.

 

The SignalRContractResolver that makes things work

The solution is the SignalRContractResolver found here.

public class SignalRContractResolver : IContractResolver
{
    private readonly Assembly _assembly;
    private readonly IContractResolver _camelCaseContractResolver;
    private readonly IContractResolver _defaultContractSerializer;
 
    public SignalRContractResolver()
    {
        _defaultContractSerializer = new DefaultContractResolver();
        _camelCaseContractResolver = new CamelCasePropertyNamesContractResolver();
        _assembly = typeof(Connection).Assembly;
    }
 
    public JsonContract ResolveContract(Type type)
    {
        if (type.Assembly.Equals(_assembly))
        {
            return _defaultContractSerializer.ResolveContract(type);
        }
 
        return _camelCaseContractResolver.ResolveContract(type);
    }
}

With this contract resolver the SignalR types are send as is and all your custom types are send using the camelCase properties the JavaScript client code is used to. Sweet right :-)

 

With the SignalRContractResolver in place all we need to do is register it with SignalR. Below is the code I use to do that.

public static void RegisterHubs()
{
    var serializerSettings = new JsonSerializerSettings
    {
        ContractResolver = new SignalRContractResolver()
    };
    var jsonNetSerializer = new JsonNetSerializer(serializerSettings);
    GlobalHost.DependencyResolver.Register(typeof (IJsonSerializer), () => jsonNetSerializer);
 
    RouteTable.Routes.MapHubs();
}

 

Enjoy!

Posted by Maurice | with no comments
Filed under: ,

 

De PowerPoint slides

En hier staat de bron code.

 

Enjoy!

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

 

 

De demo code is hier the vinden.

 

Enjoy!

Posted by Maurice | with no comments

In deze podcast spreekt Maurice de Beijer met Michaël Hompus over de software die Michaël met enkele collega's geschreven hebben voor de Serious Request actie van 3FM en het Nederlands Rode Kruis. Bij deze 6 daagse acties is meer dan 12 miljoen euro opgehaald via donaties en verzoeknummers op de website. Tijdens deze podcast, en zijn TechDays sessie in maart, vertelt Michaël hoe ze dit precies voor elkaar gekregen hebben.

Links:

 

Enjoy!

Posted by Maurice | with no comments

Recently we have been working on something new at DevelopMentor for online teaching. I still really like teaching in the classroom and I think that this is a great environment to learn new material. But it is also a very expensive and not very scalable way of learning. It typically means being away from the office for a week at a time and that can be hard on the business and on your colleagues.

 

And while the classroom is a great place to learn that will do you little good if you can’t go there. So we are starting a new way of learning on the internet. We are not the first to do so but we are doing things a bit more interactive then some. One important difference is you still get to interact with an instructor and other students. This means that you still get the benefit from interaction with your peers and the hands on experience of the instructor. And the interactive aspect is an important but missing part of a lot of the online learning experiences.

 

The first course material I have done for the LearningLine is a 4 day course on RavenDB. Using this course you can learn how to use RavenDB, complete with exercises and support if you want it, over 4 or 5 evenings. In a hurry? Just do all the material in one day, it is really up to you.  Besides RavenDB there is quite a bit more to learn on the LearningLine with more material being added every day. Both by me and by a lot of other experienced DevelopMentor instructors.

 

Want to learn more? Go and take a look at the upcoming LearningLine classes.

 

Enjoy!

Posted by Maurice | with no comments

Whatever database your are using, relational or document, there is one thing you can be certain of as soon as you get a second user of the system and that is concurrency conflicts. It may not happen often but eventually it will happen that two users load the same document, make some changes to it and save it back to the database.

There are several ways of dealing with these kind of concurrency problems:

  1. Just ignoring it and letting the second users changes overwrite the first ones
    While this isn’t advisable if the data is very important there are lots of cases where it could be an okay solution. Sure it offends the developer in us, as it should, because we are ignoring error situations. But for an end user it might not be that bad at all, specially considering that this is a really cheap option to build and the changes of it occurring are quite low. Just make sure to check with your stakeholder of this is acceptable.
  2. Using pessimistic locking of data
    This option worked quite well in the old days where a client app had a stateful connection to the database. These days that is usually not the case and with web applications that is completely impossible due to the stateless nature of the web. So this one is out.
  3. Using optimistic concurrency
    This basically means we remember the version of a document loaded and pass that along when we save the document. In SQL Server this is typically done using a rowversion. With document database we tend to interact with the database over an HTTP connection and turns out the HTTP protocol has an optimistic concurrency mechanism in the form of E-TAG’s. RavenDB can use these HTTP E-TAG’s to do optimistic concurrency checks for us.

 

Ignoring concurrency issues

This is the easy one and exactly what we get if we use RavenDB as is.

 

Consider the following code:

static void Main(string[] args)
{
    _store = new DocumentStore
    {
        Url = "http://localhost:8081/"
    };
 
    using (_store)
    {
        _store.Initialize();
 
        var id = CreateInitialDocument();
 
        var resetEvent = new ManualResetEvent(false);
 
        var tasks = new List<Task>();
        for (int i = 0; i < 2; i++)
        {
            tasks.Add(Task.Factory.StartNew(() =>
                SimpleUpdateDocument(id, resetEvent)));
        }
 
        Thread.Sleep(1000);
        resetEvent.Set();
        Task.WaitAll(tasks.ToArray());
 
 
        Console.WriteLine();
        Console.WriteLine("The result id:");
        using (var session = _store.OpenSession())
        {
            var theData = session.Load<TheData>(id);
            Console.WriteLine(theData.Data);
        }
    }
}

As you can see the code creates a new document and updates that same document in multiple threads. Then it reads it back in a prints the result.

A simple implementation of updating might look something like this:

private static void SimpleUpdateDocument(string id, ManualResetEvent resetEvent)
{
    using (var session = _store.OpenSession())
    {
        var theData = session.Load<TheData>(id);
        resetEvent.WaitOne();
        theData.Data = string.Format("Updated on thread: '{0}'", Thread.CurrentThread.ManagedThreadId);
        Console.WriteLine(theData.Data);
        session.SaveChanges();
    }
}

Basicaly we load the document, wait for each thread to have the document loaded, update it and save it back to the database. Clearly a concurrency problem arises because the last thread to save the document will try to save its changes and overwrite the others changes.

If we run the code we will see the following output. It appears that there was no error and the changes made in thread 5 where the ones that where ultimately saved.

image

Looking at the RavenDB server window you will see all interactions. Basically two post operations to save the same document right after each other.

image

Maybe this is good enough for your case and then again maybe not.

 

Using optimistic concurrency

Switching to optimistic concurrency is quite easy. All we need to do is set the UseOptimisticConcurrency property on the Advanced object of the session to true. As soon as we do this the second update, the one that would inadvertently overwrite the first one, will result in a HTTP Error 409 – Conflict. This is the result of RavenDB checking for changes using the E-TAG send with each record. If a HTTP Error 409 – Conflict is detected this surfaces in the C# code as a ConcurrencyException. By catching this ConcurrencyException we can decide what to do.

private static void ConcurantUpdateDocument(string id, ManualResetEvent resetEvent)
{
    using (var session = _store.OpenSession())
    {
        try
        {
            session.Advanced.UseOptimisticConcurrency = true;
            var theData = session.Load<TheData>(id);
            resetEvent.WaitOne();
            theData.Data = string.Format("Updated on thread: '{0}'", Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine(theData.Data);
            session.SaveChanges();
        }
        catch (ConcurrencyException ex)
        {
            Console.WriteLine(ex.Message);
            Console.WriteLine("\tExpectedETag: {0}", ex.ExpectedETag);
            Console.WriteLine("\tActualETag:   {0}", ex.ActualETag);
        }
    }
}


using this new version of the update method we will guard against concurrency issues.


If we run the code now we will see the following output:

image

 

And the RavenDB sever will also clearly show the problem.

image

 

Conclusion

Concurrency handling in RavenDB is nice and simple. By default we just get the simple last user wins behavior. This may or may not be appropriate for your situation but is easy as it requires no additional code. If you want concurrency checking all you need to do is set the UseOptimisticConcurrency property on the session to true and that session will be checked.

Nice and simple.

 

Enjoy!

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

RavenDB has a very nice feature in it being safe by default and returns just 128 documents. Now you can override these safe defaults but it is very unwise to do so. And even if you decide to do so are you really going to show a million customers to your user at the same time? I would guess not as the user would not be really happy with the response or the speed of it. In most cases using paging is a much better solution.

 

Paging through a RavenDB result set

It turns out that paging through a result set is really easy. Normally all you need to do is use the Skip() and Take() methods and filter the result set that way. Pretty easy right?

And suppose you want to display the total number of documents or pages to the user? No need to do a separate count. The RavenDB Query() function returns an IRavenQueryable instead of a plain IQueryable object. And this IRavenQueryable gives you two extra methods one of which is Statistics() with has an out argument of type RavenQueryStatistics.

This RavenQueryStatistics is interesting because it has a TotalResults property telling us how many results are returned from the query itself. There is a second useful property for paging, SkippedResults, which is needed in some cases where RavenDB will filter out duplicate results. See here for more information on when you need to use the SkippedResults property.

 

Paging in an ASP.NET MVC page

The following controller action lets us page though a large set of people with a page size.

public ActionResult Index(int pageNr = 1)
 {
     const int pageSize = 10;
     RavenQueryStatistics stats;
 
     using (var session = Global.DocumentStore.OpenSession())
     {
         var people = session.Query<Person>()
                                  .Statistics(out stats)
                                  .OrderBy(p => p.FirstName)
                                  .Skip((pageNr - 1) * pageSize)
                                  .Take(pageSize)
                                  .ToArray();
 
         ViewBag.PageNr = pageNr;
         ViewBag.PageCount = Math.Ceiling((double)stats.TotalResults / pageSize);
 
         return View(people);
     }
 }

And this is the related Razor view

@model IEnumerable<MvcApplication1.Models.Person>
 
@{
    ViewBag.Title = "People";
}
 
<h2>People</h2>
 
<h3>Page @ViewBag.PageNr of @ViewBag.PageCount</h3>
 
<ol>
    @foreach (var item in Model)
    {
        <li>
            @Html.DisplayFor(modelItem => item.FirstName)
            @Html.DisplayFor(modelItem => item.LastName)
        </li>
    }
</ol>
 
<a href="?pageNr=@(ViewBag.PageNr + 1)">Next</a>

 

Nice and simple, just the way I like it.

 

PS. Don’t like clicking on the next button button to load more data? Neither do I. One jQuery plugin that helps me there is infinite-scroll created by Paul Irish.

 

Enjoy!

Posted by Maurice | with no comments

The slides from my presentation on Practical use of HTML5 for the DotNed user group.

 

 

 

The source code can be found here.

 

There is an online demo version hosted on Azure websites here.

 

Enjoy!

In deze podcast praat Dennis Vroegop met Eric-Jan Wischmann, een certified scrum master, over de ins- en outs van Scrum. Wat is scrum? Wat betekent het voor je dagelijkse werk? Wat zijn de valkuilen?

Links:

Enjoy!

Posted by Maurice | with no comments
Filed under: ,

After installing RavenDB 2 the next step is to start saving data and load it again. Unlike SQL server we don’t need to go into the RavenDB Management Studio and create a database and tables with a schema. The database, optional but highly recommended, will be created when we first access it. And when it comes down to tables and schema RavenDB is much simpler, all it does is store documents. A document doesn’t have a schema enforced so we don’t need to define one up front. Instead we just save some data and load it again.

The document to store

Even though RavenDB doesn’t require us to define the document structure we are using C# at the front end and in C# we usually define our data structure using classes. In this example we are going to store people using the following C# class:

   1: class Person
   2: {
   3:     public string Id { get; set; }
   4:     public string FirstName { get; set; }
   5:     public string LastName { get; set; }
   6: }

We are going to provide the first and last name and the Id property is for use with RavenDB. In fact we could leave the Id out, RavenDB would not care, but it would be harder to load a single document if we did.

 

The RavenDB DocumentStore

Before we can start working with the RavenDB server we first need to create an instance of the RavenDB DocumentStore. This is a relatively expensive object to create and normally in an application you only create a single and keep a reference to it. It is thread safe so a singleton will work just fine even in an ASP.NET application. The minimum information the DocumentStore needs is the url of the RavenDB server, in this case the default location of http://localhost:8080/. Additionally we can specify a default database to use, in this case people. This database will be created automatically when needed.

   1: var store = new DocumentStore
   2: {
   3:     Url = "http://localhost:8080/",
   4:     DefaultDatabase = "people"
   5: };
   6: store.Initialize();


The RavenDB DocumentSession

When we start doing any actual work with the RavenDB database we need to do so in the scope of a session. To create a new session we can call the DocumentStore.OpenSession() function. This session needs to short lived and only be used on a single thread. With this session we can persist data to the database and load it again.

   1: using (var session = store.OpenSession())
   2: {
   3:     var person = new Person()
   4:     {
   5:         FirstName = "Maurice",
   6:         LastName = "de Beijer"
   7:     };
   8:     session.Store(person);
   9:     Console.WriteLine("Storing person with ID: {0}", person.Id);
  10:     session.SaveChanges();
  11:     id = person.Id;
  12: }

Note that we need to call SaveChanges for the data to be persisted. If we forget to do this the session object will be disposed and the new person will not be saved.

 

Loading the document again is simple. Just create a session and use the Load() with the document id.

   1: using (var session = store.OpenSession())
   2: {
   3:     var person = session.Load<Person>(id);
   4:     Console.WriteLine("Loaded: {0} {1} {2}",
   5:         person.Id, person.FirstName, person.LastName);
   6: }


If we don’t know the document id, or we just want to load multiple document we can also query the document store using the Query() function.

   1: using (var session = store.OpenSession())
   2: {
   3:     var people = session.Query<Person>();
   4:     foreach (var person in people)
   5:     {
   6:         Console.WriteLine("Loaded: {0} {1} {2}",
   7:             person.Id, person.FirstName, person.LastName);
   8:     }
   9: }


Running the application gives us the following output:

image

 

What does RavenDB store for us?

If we open the RavenDB Management Studio and navigate to the person stored we can see what data is actually stored. As you can see below the data is actually saved in a JSON format. The C# type isn’t used at all.

image

In fact we can load this document without the .NET client library with a simple HTTP get request:

 

http://localhost:8080/databases/people/docs/people/1

This will simply return the data as a JSON response in the browser.

image

 

It turns out RavenDB stores more than just the data we send, it also stores some metadata. The most important parts of metadata are the RavenDB entity name, the C# class name we used without the namespace, and the CLR type, the full type name for the C# class we created.

image

 

Enjoy!

Posted by Maurice | with no comments
Filed under: ,

Donderdag 24 januari 2013 doe ik weer een presentatie over HTML5 voor de DotNed gebruikersgroep.

 

Op dit moment is HTML5 een van de grote hypes. Door de HTML5 standaard te gebruiken gaan we alles anders doen op het web. Uiteraard gaat alles goed en vanaf nu werkt alles gewoon zoals verwacht op alle browsers hetzelfde. En zo zijn er nog wel meer fabeltjes.

Zoals iedereen, die al langer voor het web ontwikkelt, weet dat dit tot nu toe nog nooit het geval is geweest. En zelfs als dat in een wereld met perfecte browser leveranciers waar zou zijn dan zitten we nog met het feit dat niet iedere gebruiker zijn browser snel update. Zo gebruikt meer dan 10% van de gebruikers nog Internet Explorer 8.0 als hun browser en dat is nu niet echt een browser die de HTML5 standaard goed ondersteunt.

Betekent dit nu dat we helemaal niet met HTML5 aan de slag kunnen? Uiteraard kan dat wel, alleen moeten we goed kijken naar welke onderdelen we gebruiken. In deze sessie laat Maurice de Beijer zien hoe je een bestaande web applicatie kan vernieuwen met HTML5 onderdelen maar op een manier waarop oudere browsers toch gewoon blijven werken.

 

Ik hoop iedereen daar te zien :-)

Posted by Maurice | with no comments
Filed under: ,
More Posts Next page »