The Todo samples are introductory tutorials on client-side JavaScript development with Breeze. The server is not the point. But the Todo application needs a server to demonstrate its capabilities.
That server, the subject of this topic, is the same for all Todo Sample variations. It is a simple ASP.NET Web Application running a Breeze Web API controller on IIS that queries and saves data to a SQL Server database via an Entity Framework "Code First" model.
We stress that BreezeJS itself is not wedded to this particular combination of technologies. Other Breeze samples will demonstrate Breeze working with other server-side technologies. We settled on ASP.NET, IIS, Web API, Entity Framework, and SQL Server for these Todo samples because they are easy-to-use and widely accepted within the .NET community ... the first community to adopt Breeze as its own.
The Todo samples were built from scratch in Visual Studio 2012 with the ASP.NET Empty Web Application template. That template produces a single barebones project with no ASP.NET MVC, no Razor engine, no Entity Framework, no Web API. It is automatically configured to run on IIS Express.
We reset the target .NET framework to .NET 4.0 to make these samples available to developers who have not yet upgraded to 4.5. You're welcome to retarget your copies to .NET 4.5 where they work fine as well.
Could we have used an MVC template (MVC Empty, MVC Web API, MVC SPA, ...)? Sure. In fact we did start with the MVC Web API template in earlier versions. And those templates will be a popular foundation for many applications. But the MVC templates add a ton of material ... including MVC itself ... that we aren't using in this Todo sample. We opted for the cleanest, leanest ASP starting point.
We installed the latest "Breeze.MVC4WebApi" NuGet package. Your copy may have an older version of that package; please feel free to upgrade it yourself.
The "Breeze.MVC4WebApi" NuGet package installs the ASP Web API, Entity Framework 5.x, the Breeze.NET components in support of EF and Web API, and the BreezeJS JavaScript files (Breeze and Q).
The Todo data are stored in a SQL Server Compact Edition 4 (SQL Server CE) database. We installed it and a companion EF driver via the "EntityFramework.SqlServerCompact" NuGet package.
We picked SQL Server CE because many developers don't or won't install any version of the SQL Server on their machines ... and CE deploys as a referenced DLL, not as a Microsoft product. To paraphrase Microsoft's description, "SQL Server CE is a free, embedded database with a small footprint that supports private deployment of its binaries within the application folder."
The Todo database itself is not included in the download. Rather the application (re)generates it from scratch, with mock data, every time the server starts. You'll find it as the hidden "Todos.sdf" file in the App_Data folder.
All third party libraries are in the Scripts folder. In our own applications, we tend to put them in to a Scripts/lib folder. But NuGet insists on deploying them to the Scripts directory and we let that be.
We installed jQuery and toastr with NuGet in all sample variations. We use the toastr library to display process and error messages in pop up "toast" windows.
For the Todo-Knockout variations we installed the "knockoutjs" NuGet package. For the Todo-AngularJS variations, we downloaded and added angular.js and angular.min.js directly to the Scripts directory; the AngularJS NuGet package installs far too many unwanted scripts for our tastes.
For Todo-Require we installed the "RequireJS" NuGet package.
The content folder holds three CSS files
CSS file | Description |
---|---|
reset | Eric Meyer's CSS that clears ambient settings. Copied from his web site. |
toastr | Formatting for the toastr pop-ups. Installed by the "toastr" NuGet package |
todo | Formatting specifically for this application. |
The Models folder holds the business model for the application.
TodoItem.cs defines the one and only entity class. It is small and simple enough to reprint in full:
public class TodoItem { public int Id { get; set; } // 42 [Required, StringLength(maximumLength: 30)] // Validation rules public string Description { get; set; } // "Get milk" public System.DateTime CreatedAt { get; set; } // 25 August 2012, 9am PST public bool IsDone { get; set; } // false public bool IsArchived { get; set; } // false }
Notice the System.ComponentModel.DataAnnotations attributes, Required and StringLength, decorating the Description property. They impose minimum and maximum lengths for the TodoItem.Description - validations that are enforced by Entity Framework on the server and by BreezeJS on the client. The Breeze.Net detects these validations and includes them in the metadata it sends to the client.
TodosContext is an Entity Framework Code First DbContext for modeling and database access. It too is trivially simple:
public class TodosContext : DbContext { // DEVELOPMENT ONLY: initialize the database static TodosContext() { Database.SetInitializer(new TodoDatabaseInitializer()); } public DbSet<TodoItem> Todos { get; set; } }
It exposes a single st DbSet property with which to query TodoItem.
The static constructor ensures that the database is (re)built from scratch with demo data when the server is launched. The database initialization class, TodoDatabaseInitializer.cs, is too big to reprint here but it is easy to read.
When the application requests data from the TodosContext, it finds a connection string for the database in the Web.config under the name "TodosContext".
<connectionStrings> <add name="TodosContext" connectionString="Data Source=|DataDirectory|Todos.sdf" providerName="System.Data.SqlServerCe.4.0" /> </connectionStrings>
The Controllers folder holds the sole Web API controller, TodosController.
Web API developers will not be surprised to learn that there is only one controller; afterall, there is only one entity type. But, this being a Breeze Web API, there probably would be only one controller even if the model had twenty entity types.
The todosController is a tad too big to reprint in full. We'll break it down in parts.
First, here is the essence of it:
[BreezeController] public class TodosController : ApiController { // ~/api/todos/Metadata [HttpGet] public string Metadata() { return _contextProvider.Metadata(); } // ~/api/todos/Todos // ~/api/todos/Todos?$filter=IsArchived%20eq%20false&$orderby=CreatedAt [HttpGet] public IQueryable<TodoItem> Todos() { return _contextProvider.Context.Todos; } // ~/api/todos/SaveChanges [HttpPost] public SaveResult SaveChanges(JObject saveBundle) { return _contextProvider.SaveChanges(saveBundle); } }
This would have been the entire controller implementation ... if we hadn't added extra material for deploying and managing this demo on our servers at todo.breezejs.com.
The [BreezeController] attribute adorning the class is essential. It configures the Web API specifically for this controller.
There are three action methods - MetaData, Todos, and SaveChanges -, each preceded by a comment illustrating the kind of HTTP request handled by that method. Each is adorned with a Web API, System.Web.Http attribute identifying which HTTP methods can be routed to this action.
Action | Http Method | Description |
---|---|---|
Metadata | GET | Returns BreezeJS metadata describing the model so the Breeze client can create, materialize, validate and save TodoItems. |
Todos | GET | Returns an IQueryable of all TodoItems in the database which can be filtered, sorted, and paged on the database by client request. |
SaveChanges | POST | Receives a bundle of entity information describing one or more entities (TodoItems in this case) that should be created, updated, or deleted. All standard Breeze client save requests are routed to this method. |
Almost all Breeze Web API controllers will have a single Metadata and a single SaveChanges method, regardless of the number of entity types it supports.
If there were more entity types to query ... and you wanted the client to be able to query them ... you would add more query methods like Todos.
Notice that all three methods delegate to an instance of EFContextProvider.The EFContextProvider is a helper class that makes it easier for Breeze Web API controllers to interact with an Entity Framework DbContext (or ObjectContext).
This provider wraps an instance of TodoContext, the application model's DbContext (described above). The provider's Context property exposes this DbContext directly to controller query methods such as Todos, making it easy to return a DbContext's DbSet property as the action result.
Creating metadata for the Breeze client based on an Entity Framework model is no small task. The provider's Metadata method does the job.
The provider's SaveChanges method can turn the incoming Json.NEt object representing an entity changeset into a database update via the Entity Framework.
Read more about the EFContextProvider here.
The rest of the controller - perhaps as much as half of the controller code - has nothing to do with the Todo application per se. You probably wouldn't include any of it in your applications.
We need it because we host this sample on our servers at todo.breezejs.com. People trying the application tend to enter a lot of junk data some of which may be offensive. The Purge method deletes all TodoItems in the database. The Reset method purges the database and re-creates the demo data set.
A BreezeJS EntityManager can't call these methods itself. The only HTTP POST an EntityManager can send is a SaveChanges request. But the client application can ... with a simple AJAX call ... in the same way it can call any Web API method. And the Todo client application does bind HTML links to dataservice.js methods that make purge and reset requests.
There is also timer logic at the top and bottom of the controller to purge and reset the database automatically every 20 minutes. You are unlikey to want to do this to your production database.