As I’ve already stated in my previous post, i chose Angular as the default JS framework for my future projects. Angular leaves to your choosing the technology for data manipulation, and since i like robust solutions for my data needs, i went with Breeze.
John Papa gives probably the best explanation on why Breeze is so powerful and practical
But one thing that really has me excited about breeze is the thing that some people hate about it and that is a “Metadata()” endpoint.
What is metadata endpoint?
Metadata endpoint is a service method that a Breeze client application calls to get all the info about entities it has to keep track off, including property names and types, validation, keys, references, object graph etc. The method is called once per app initialization, and the payload can be pretty heavy, but it saves a lot of coding.
The reason i’m so interested in it is that it lets me share basic entity descriptions and validation between client and server, and what’s more, it also lets me save my own custom metadata to feed it, which i will definitely use when creating dynamic business entities in my future project.
Theoretically, Breeze should also be a good fit for Angular because of Angular’s notorious non-scalability when it comes to number of bindings. To keep the app snappy, you have to keep bindings in-check, so huge grids of control-bound data are out of the question. But then you run into a problem of dirty-checking and keeping data up-to-date when having multiple references to same data, and doing lots of manual work which you wanted to avoid by using Angular in the first place. Breeze keeps all those points covered, so i think i can get away with binding angular on just a few key properties and actions, and let Breeze handle the rest.
This is all still IN-THEORY, but i will look into it pretty soon and get back to you with results. Other than that, Breeze is extremely flexible, it can consume literally ANYTHING you throw at it, from OData, Queryable endpoints, pojos, DTOS, from any source which uses HTTP. So you have all the flexiblity in the world to start fast and lean by leveraging tight integration with entity framework, and move gradually to using classic REST endpoints with perhaps MongoDb as persistence.
Quick start
For a quick start with Angular and Breeze I warmly recommend Hot towel Angular Breeze nuget package. It’s a pretty neat layout for an SPA.
After installing i made a few modifications:
1. Instead of firing up SPA by calling index.html, i moved most of the logic to Index.cshtml
2. For my own needs, I moved top navigation bar to ASP.NET view (server-side) because i plan on having lots of smaller SPAs instead of one big one, and i will show links to those in my top bar.
3. For every SPA, you have to reference ALL the the .js files you plan to use in your index.html. That’s my conclusion so far but there’s probably some more elegant solution somewhere.
4. One HUGE pain in the neck i had is that I would get 500 errors from server with a completely blank page, just the header. Debuging didn’t help because all breakopioints would get hit, and no error i could see was thrown. On thing that finally helped me was IntelliTrace, a feature that i would regularly turn off in previous versions of Visual Studio. It showed that my server was throwing “Entry point was not found.” error on Newtonsoft.Json assembly. I previously had to update Json.NET while setting up my environment so i suspected that could cause problems.
It turns out that regardless of having a newer version of Json.NET packaged in the solution, some assemblies would target the older one stored in GAC, and then you would get a version mismatch. A good explanation of the problem can be found here. The solution of the problem is pretty simple, you have to update your Web.Config where you define which Json.NET minimum version to use:
<dependentAssembly> <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" /> <bindingRedirect oldVersion="0.0.0.0-4.5.0.0" newVersion="4.5.0.0" /> </dependentAssembly>
to…
<dependentAssembly> <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" /> <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" /> </dependentAssembly>
5. Breeze is not hooked up by default in this template, you have to modify a few files. First you have to modify datacontext.js and include entityManagerFactory. Something like this…
(function () { 'use strict'; var serviceId = 'datacontext'; angular.module('app').factory(serviceId, ['common','entityManagerFactory','breeze','logger', datacontext]); function datacontext(common, entityManagerFactory,breeze, logger) { var $q = common.$q; var mngr = entityManagerFactory.newManager(); var service = { getPeople: getPeople, getMessageCount: getMessageCount, getPartners:getPartners }; return service; function getMessageCount() { return $q.when(72); } function getPeople() { var people = [ { name: 'John', lastName: 'Papa', age: 25, location: 'Florida' }, { name: 'Ward', lastName: 'Bell', age: 31, location: 'California' }, { name: 'Colleen', lastName: 'Jones', age: 21, location: 'New York' }, { name: 'Madelyn', lastName: 'Green', age: 18, location: 'North Dakota' }, { name: 'Ella', lastName: 'Jobs', age: 18, location: 'South Dakota' }, { name: 'Landon', lastName: 'Gates', age: 11, location: 'South Carolina' }, { name: 'Haley', lastName: 'Guthrie', age: 35, location: 'Wyoming' } ]; return $q.when(people); } function getPartners() { var qry = breeze.EntityQuery.from("Partners").orderBy("name"); var promise = mngr.executeQuery(qry).catch(queryFailed); return promise; } function queryFailed(error) { logger.logError(error.message, "Query failed"); throw error; // so downstream promise users know it failed } } })();
This is the biggest difference from the regular samples you will find. Most of other samples don’t use entityManagerFactory.
Notice how i use Angular’s dependency injection to reference entityManagerFactory. I use that factory to make an entityManager used for data retreival. What i’m very glad to see is the concepts from silverlight (like query objects in getPartners) making it into Breeze. Makes me feel right at home:). After you’ve done that you’ll start getting some excetpion about failing to resolve dependencies. You also have to hook up breeze itself into your application.
You will also have to configure your endpoint and some other stuff in your config.js
(function () { 'use strict'; var app = angular.module('app'); // Configure Toastr toastr.options.timeOut = 4000; toastr.options.positionClass = 'toast-bottom-right'; // For use with the HotTowel-Angular-Breeze add-on that uses Breeze var remoteServiceName = 'breeze/AppContext'; . . .
The remoteServiceName is the most important one for breeze, this is a relative URL To your breeze service.
The last piece of the puzzle is hooking up breeze in your app.js, which is something already described in lots of sample apps, but here it is:
(function () { 'use strict'; var app = angular.module('app', [ 'breeze.angular', // Angular modules 'ngAnimate', // animations 'ngRoute', // routing 'ngSanitize', // sanitizes html bindings (ex: sidebar.js) // Custom modules 'common', // common functions, logger, spinner 'common.bootstrap', // bootstrap dialog wrapper functions // 3rd Party Modules 'ui.bootstrap' // ui-bootstrap (ex: carousel, pagination, dialog) ]); // Handle routing errors and success events app.run(['$route', function ($route) { // Include $route to kick start the router. }]); })();
The first line, “breeze.angular”, is what’s important. You also have to reference all those files of your SPA in your index.html page. I use ForLoop.HtmlHelper for this, so that all the javascript references and blocks end up at the end of the page. The following is the complete reference for my sample app, you don’t need all of it.
@using (@Html.BeginScriptContext()) { Html.AddScriptFile("~/scripts/angular.js"); Html.AddScriptFile("~/scripts/angular-animate.js"); Html.AddScriptFile("~/scripts/angular-route.js"); Html.AddScriptFile("~/scripts/angular-sanitize.js"); Html.AddScriptFile("~/scripts/breeze.debug.js"); Html.AddScriptFile("~/scripts/breeze.angular.js"); Html.AddScriptFile("~/scripts/toastr.js"); Html.AddScriptFile("~/scripts/moment.js"); Html.AddScriptFile("~/scripts/ui-bootstrap-tpls-0.10.0.js"); Html.AddScriptFile("~/scripts/spin.js"); // <!-- Bootstrapping --> Html.AddScriptFile("app/app.js"); Html.AddScriptFile("app/config.js"); Html.AddScriptFile("app/config.exceptionHandler.js"); Html.AddScriptFile("app/config.route.js"); // <!-- common Modules --> Html.AddScriptFile("app/common/common.js"); Html.AddScriptFile("app/common/logger.js"); Html.AddScriptFile("app/common/spinner.js"); //<!-- common.bootstrap Modules --> Html.AddScriptFile("app/common/bootstrap/bootstrap.dialog.js"); //<!-- app --> Html.AddScriptFile("app/admin/admin.js"); Html.AddScriptFile("app/dashboard/dashboard.js"); Html.AddScriptFile("app/templates/templates.js"); Html.AddScriptFile("app/layout/shell.js"); Html.AddScriptFile("app/layout/sidebar.js"); //<!-- app Services --> Html.AddScriptFile("app/services/datacontext.js"); Html.AddScriptFile("app/services/directives.js"); Html.AddScriptFile("app/services/entityManagerFactory.js"); }
And that’s it! I managed to show my first table with this kind of setup. I just wanted to point out some relevant points i couldn’t find anywhere else to make the hook-up succesful, you should definitely have a look at other sampple applications like Todo-Angular on the Breeze site.
Nate May 22 , 2014 at 8:36 pm /
Can you make your version available? I am trying to using this template to load data from the entity framework and I am not sure how this is suppose to bind the EF results to Breeze. Thanks
admin Jun 08 , 2014 at 8:37 pm /
Nate, i suggest you take a look at the setup on breeze.js website, that should give you a good head start.
Raul Nov 11 , 2014 at 3:29 pm /
Sooo 7 months on what are your thoughts on Breeze? Six months ago it was on my radar but I don’t see much community support now that I’m ready to dig into it. Agree/Disagree?
Slobodan Aug 15 , 2015 at 9:14 am /
Great post Bruno,
if you are still interested in some more elegant solution for referencing .js files in index.html (point 3), take a look at: https://oclazyload.readme.io
It made my angular life easier.
Any new thoughts about breeze and its future?