TempHire is a reference application that has been designed from the ground up to scale to the needs of medium-to-large business applications. It demonstrates a range of architectural and design patterns, including repository patterns, Model-View-ViewModel (MVVM) presentation style, view composition, multi-screen navigation, data-binding, reusable UI components, validation, and multiple EntityManagers for sandbox editing, and cache management.
Being a reference app, we’ve kept TempHire manageable and limited its scope to something that highlights our enterprise design decisions without too many distractions. TempHire demonstrates a single Resource Management module in action, but you can see how additional modules (Scheduling, Customer Management, etc.) could easily be built on this framework.
Enterprise applications (line of business applications or LOBs) typically have task-oriented UIs and complex, cross-functional, workflows. They need multiple views and require considerable navigation. Given only a few screens, screen composition, decomposition, and data-binding to complex data models can get out of hand in a hurry.
Likewise, LOBs need to able to read, modify, and create data, so determining how to shuttle data back and forth between the UI and the back-end becomes yet another challenge. There’s a lot of tedious code involved in turning all that raw data into business objects and moving them to and from the client.
Putting all of the pieces together is enough of a challenge on traditional, relatively static, desktop clients; but more and more frequently, product requirements demand that these apps go cross-platform and work on desktops, tablets, and multiple mobile devices.
How do you design and write LOB apps that can handle real-world complexity? How do you build apps that can be easily maintained and extended over multiple years? How do you go cross-platform without hiring an army of developers to rewrite your code for multiple clients?
TempHire reduces complexity by leveraging frameworks like Durandal for presentation and libraries like Breeze for data management, so developers can focus on solving business problems rather than the plumbing and wiring.
Even better, through the use of proven architecture and design patterns, multiple developers can work independently on specific views, models, and workflows without impacting other modules.
The DomainModel is the main model for all of the application data. TempHire’s domain model contains all of its entity classes, an entity base class, and a DbContext file.
Let’s look at AddressType as an example of one of Temphire’s entity classes. It’s a Code First class that has four properties.
TempHire uses a base class that all the entities, directly or indirectly, inherit from (EntityBase.cs). The nice thing about Code First is that TempHire can add common functionalities to the base class that will be applied to all of the entities in the domain model. Because these functions are in the base class, TempHire doesn’t need to add them to derived classes. Everything is inheritable.
You can see this in action by the way that TempHire handles concurrency checking. It’s located in the base class and is inherited by every entity.
TempHireDbContext demonstrates how we map TempHire’s domain model to a database using EntityFramework Code First. TempHire tells EF what its entitysets are, and sets a few initialization strategies (e.g. dropcreatedatabaseifmodelchanges). To be very clear, we’ve built TempHire as a demo app ... and in this context, this makes sense. Don’t drop your database in a production application!
Temphire uses projections and DTOs where applicable to improve performance and to move complex queries to the server, where implementing them in LINQ is a lot easier. You can see this in action on the master details screen:
Frequently you’ll see grids like this populated by entities, but we don’t do that here. Instead, this grid uses a projection query that cherry picks the information from an object graph, condenses it, and sends it down the wire. Projections are a simple way to enhance performance, and your customers who are connecting via an EDGE network will be happy you did.
With the domain model behind us, let’s take a look inside the app itself.
The App folder contains the core components of the TempHire client: Durandal, Client Services, ViewModel code, the HTML Views, and main.js, the script that bundles the app’s scripts into a single package.
We’re assuming you’re familiar with the basics, so the most interesting components here are likely App/Durandal and App/ Services.
Durandal, Rob Eisenberg’s excellent SPA framework, leverages Knockout and Require. Durandal takes care of the front-end plumbing and makes screen composition and management fast and easy. Even better, Durandal promotes architecture practices that will positively impact scalability and long term maintenance. Long story short, Durandal saves a ton of time and hassle in regards to architecturally sound front-end development.
Entitymangerprovider.js offers a CreateManager method for TempHire to call whenever it needs a new EntityManager instance—something it does frequently as each UOW must spin up a new EntityManager. Logger.js takes care of TempHire’s logging functions, Repository.js is responsible for the configuration of UOW Repositories, and Unitofwork.js is responsible for the configuration of the UOW themselves.
App_Start contains BreezeWebApiConfig.cs, BundleConfig.cs, and InfrastructureConfig.cs. These files run at the beginning of the server launch sequence and register their applicable routes. BreezeWebApiConfig routes Breeze client requests to the Breeze controller, and InfrastructureConfig registers the resource bundles via the BundleConfig helper class. Additional infrastructure configuration can be added here later.
All of TempHire’s content files (CSS and images) are stored in the appropriately named Content folder. This is a good time to mention that TempHire uses Twitter Bootstrap, an excellent template for quickly standing up a modern front-end.
HTML, CSS, UI elements, responsivity—yeah, Bootstrap takes care of all of that.
The default controller is responsible for delivering the common metadata. Query and Save logic is to the respective module controllers.
The LookupBundle is a DTO used to ship global read-only entities such as lookup data to the client in one shot. A client requests this data once at the beginning and holds it in a global cache. Every EntityManager when first created is pre-seeded with this global lookup data.
The ResourcMgtController defines the query and save endpoints for the resource management module. Each module gets its own controller in order to keep their size manageable and combine related functionality in one place.
Much as like we did client-side, the server-side also uses the unit of work pattern to structure the query and save logic and keep it external to the controllers. This way the controllers stay small enough and the business logic is encapsulated in the corresponding server-side unit of work.
Bootstrap adds front-end pizazz with a variety of widgets, transitions, buttons, etc. It should go without saying that they all work seamlessly with the Twitter Bootstrap CSS (See Content). The various GUI elements are documented at twitter.github.io.
Breeze excels at data management and takes care of the Model –the M in MVVM. Breeze queries, saves, and manages all data interactions between client and server. Breeze EntityManagers make writing TempHire’s Unit of Work patterns considerably easier.
jQuery is a dependency for some of TempHire’s libraries and templates. Bootstrap, Breeze, Durandal, and Sammy rely on one bit of jQuery or another.
Knockout manages the data-binding and dependency tracking for the presentation layer—the ViewModel—the VM in MVVM. Even better, it is intimately tied to Require and Sammy via the Durandal framework, making much of the front-end wiring easier.
q assists in managing asynchronous operations through CommonJs promises.
Sammy is a small, yet powerful, framework for building SPAs like TempHire. (Sammy refers to them as single-page AJAX applications, but SPAJAX is a bit of a mouthful.) TempHire uses Sammy primarily for its navigation and routing functionality.
Toastr displays process and error notifications in "toast" windows that float up from the lower right to let you know what TempHire is doing at any given time.
All of TempHire’s persistence ignorance is built into the server-side services using Unit of Work (UOW) patterns.
The UOW is a design pattern that encapsulates anything from simple tasks to complex workflows. The UOW can be short or long lived, may involve retrieving data, modifying data, creating new data, performing business logic, checking business rules, and saving or rolling back changes.
An EntityManger is spun up for each UOW and takes care of the configuration, authentication, and connection details, while the UOW’s Repository handles the business logic that governs access to a specific type of entity.
UOWs make it possible to highly optimize the fetching strategy for a given entity type. e.g. A Repository for a static type such as Color can be optimized to load all colors on the first request and serve future requests directly from the cache instead of making additional trips to the server.
UOWs can be shared between ViewModels if different parts of the UI work with the same data, but each UOW remains a unique sandbox.
TempHire uses UOWs as transaction boundaries—each with customized responsibilities that lead to an organized codebase that’s easier to maintain and improve over time.
TempHire's is an ASP.NET Web Application. The server hosts all the client-side assets as well as an ASP.NET MVC4 Web API service that queries and saves to a SQL Server database with the help of an Entity Framework Code First model. We used ASP.NET because it’s quick and effective for enterprise developers familiar with the Microsoft stack. It’s also helpful that Breeze ships with components that ease development of Web API and Entity Framework back-ends.