Oak

Frictionless development for ASP.NET MVC single page web apps. Prototypical and dynamic capabilities brought to C#.


Project maintained by amirrajan Hosted on GitHub Pages — Theme by mattgraham — Logo by setiART*

What is Oak?

Single page web apps are becoming the norm as opposed to the exception. And with that comes a large part of your code base existing on the client side with a lot of JavaScript, JSON and async HTTP. Oak gives you a way to quickly build these kind of apps by:

Publications and Credibility

Get Started

Oak has full documentation, screencasts, sample apps, and an interactive tutorial to help developers ramp up quickly. Here is what you need to do:

  1. Watch the screen casts (each ~10 mins long)
  2. Install the prerequisites
  3. Run through the interactive tutorial

After your interest is piqued.

  1. Get the sample apps running
  2. Read the wiki to wrap up (it's succinct and very helpful)
  3. Let me know what you think

First Time (Prerequisites)

Start Coding Now - Bootstrapped Solution With Oak

Run the following commands to quickly create a fully loaded .Net solution bootstrapped with Oak. Using a command prompt that supports ruby (be sure to run the command prompt as an administrator):

warmup http://github.com/amirrajan/loam Blog
Downloads a .Net sln bootstrapped with Oak, ~20MB.

=== OR if you want a solution that includes UI Automation ===

warmup http://github.com/amirrajan/walkingskeleton Blog
Downloads a .Net sln bootstrapped with Oak and Selenium libraries, ~70MB.
If this is your first time trying Oak, stick to the first warmup command.

After the warmup command runs (speed of download is based on internet connection), run the following:

cd Blog
start Blog.sln (this sln is VS 2013, install the express edition if needed)
rake (builds the .net app)
rake server (starts iis express)
sidekick.bat (starts your feedback loop)

Interactive Tutorial

Oak comes with an interactive tutorial. Once you have taken the steps above, go to http://localhost:3000 and try out Oak interactively.

Growl Support for Continuous Development

To get the most out of the Interactive Tutorial, take the time to install Growl for Windows with a nice notification theme:

Jump to the Sample Apps


Screencasts and Feature List - It's all about reducing friction


Frictionless Development Cycle - Oak's Walking Skeleton

Oak has an addicting development life cycle that incorporates rapid application development, fast feedback loops, testing, and UI automation. Watch the video to see Oak in action:

Frictionless Development Cycle - Oak's Walking Skeleton from Amir Rajan on Vimeo.


Frictionless Data Access, Change Tracking and Validation - Oak's dynamic Entity Model: Cambium

Oak has a dynamic entity model called Cambium which is amicable to dynamic structures (ie JavaScript classes). Cambium makes validating, detecting changes, saving, retrieving, and defining associations ridiculously easy. Check out the Sample Apps and the Wiki for more info. Here is a sneak peek at what Cambium can do:

Validations

dynamic blog = new Blog(); //new up a blog, validate
blog.Name = "";
blog.IsValid(); //this would be false
blog.FirstError(); //this would return "Name is Required"

public class Blog : DynamicModel
{
    //validation, name is required
    IEnumerable<dynamic> Validates() {
        yield return new Presence("Name");
    }

    public Blog(object dto) : base(dto) { }
    public Blog() : base() { }
}

Associations

Blogs blogs = new Blogs(); //data access by convention
Comments comments = new Comments(); //data access by convention
dynamic blog = new Blog();
blog.Name = "Blog Name";
blog.Id = blogs.Insert(blog); //inserts into the database returns an Id
var comment = blog.Comments().New(new { Body = "new comment" });
comments.Insert(comment); //inserts comment into database

public class Blogs : DynamicRepository 
{
    public Blogs() { Projection = d => new Blog(d); }
}

public class Comments : DynamicRepository { }

public class Blog : DynamicModel
{
    //a blog has many comments
    IEnumerable<dynamic> Associates() {
        yield return HasMany(comments);
    }

    Comments comments = new Comments();
    public Blog(object dto) : base(dto) { }
    public Blog() : base() { }
} 

Frictionless, Zero Class Data Access - DynamicDb

DynamicDb gives you instant data access to your database without the need to declare any classes and wire them to an ORM, ie. zero class data access. It will even find table relationships for you. Given a Blogging database with the following schema:

You get the ability to do this:

//new up a DynamicDb, be sure to cast it as dynamic
dynamic db = new DynamicDb();

//insert an Author
var authorId = db.Authors().Insert(new { Name = "An Author" });

//create a Profile for Author
db.Profiles().Insert(new { authorId, Email = "user@example.com" });

//insert a blog and associate it to Author
var blogId = db.Blogs().Insert(new { Title = "A Blog", authorId });

//insert 2 comments associated with Blog
db.Comments().Insert(new { Text = "comment 1", blogId });
db.Comments().Insert(new { Text = "comment 2", blogId });

and this:

//this will give you an IEnumerable<dynamic> of Blogs
var blogs = db.Blogs().All();

foreach(var blog in blogs)
{
    //accessing the Author through a BelongsTo relationship
    Console.WriteLine(blog.Author().Name);

    //accessing the Author's Profile through a HasOne relationship
    Console.WriteLine(blog.Author().Profile().Email);

    //accessing the Comments for the Blog through a HasMany relationship
    foreach(var comment in blog.Comments())
    {
        Console.WriteLine(comment.Text);
    }
}

More info can be found on the DynamicDb wiki page

Frictionless Schema Generation - Oak's Seed

Schema generation should be simple. Period. Here's what simple looks like:

var seed = new Seed();

//create blogs table
seed.CreateTable("Blogs",
    seed.Id(), 
    //seed.Id() is an alias for 
    //new { Id = "int", Identity = true, PrimaryKey = "true" }
    new { Name = "nvarchar(255)" },
    new { Body = "nvarchar(max)", Default = "Lorem Ipsum" }
).ExecuteNonQuery(); 
//Seed's CreateTable method returns a string that's valid sql,
//ExecuteNonQuery will execute that string

//create comments table
seed.CreateTable("Comments",
    seed.Id(), 
    new { BlogId = "int", ForeignKey = "Blogs(Id)"
    new { Body = "nvarchar(max)", Nullable = false }
).ExecuteNonQuery();

//ad hoc
"drop table Foobar".ExecuteNonQuery();

Frictionless Testing - NSpec and SpecWatchr

Oak is bootstrapped with NSpec and SpecWatchr. Driving out your implementation with tests ensures that you have a maintainable code base.

Frictionless UI Automation - Canopy

Oak is bootstrapped with a UI automation framework called canopy. With the increased use of client side javascript, UI automation tools are absolutely necessary. Canopy gives you a terse DSL written in F#. Very easy to pick up!

open canopy
start "firefox"
url "http://google.com"
"input[type='text']" << "hello world"
click "input[type='button']"

Frictionless Debugging - Stack Trace Preview

If an exception is thrown in the web application or within your tests. A visualization like this one can be generated to quickly view stacktrace + source. The 10+ year old Yellow Screen Of Death just got a huge facelift!

Frictionless Dev Environment Setup - RakeDotNet

Oak comes installed with a suite of rake scripts that will build your solution, deploy your web app, run NSpec tests and run UI automation tests. These scripts can be leveraged directly by your build servers. Using a command prompt that supports ruby (be sure to run the command prompt as an administrator), you can type any of the following commands:

rake
  builds and deploys your application

rake server
  starts up iis express pointing to your deploy directory

rake simulate_load_balance
  sets up iis express in a round robin load balanced configuration

rake reset
  regenerates your schema

rake sample
  inserts sample data into your db to help with development

rake export
  exports your schema to a set of sql scripts

rake tests
  runs all tests

rake ui
  runs ui automation

Frictionless Scaffolding - scaffold.rb

Oak comes bootstrapped with a suite of rake scripts that help you scaffold common files in your solution. These scripts can be leveraged by you to quickly generate classes. Using a command prompt that supports ruby (be sure to run the command prompt as an administrator), you can type any of the following commands:

all scripts are customizable and are located in .\scaffold.rb

rake gen:controller[name]
    adds a controller class to your mvc project
    example: rake gen:controller[Blogs]

rake gen:model[name]
    adds a dynamic model class to your mvc project
    example: rake gen:model[Blog]

rake gen:repo[name]
    adds a dynamic repository class to your mvc project
    example: rake gen:repo[Blogs]

rake gen:repo_model[repo_and_model_name]
    adds a dynamic repository with a projection to a dynamic model
    example: rake gen:repo_model[Blogs:Blog]

rake gen:script[name]
    adds javascript file to your mvc project
    example: rake gen:script[index]

rake gen:test[name]
    adds a test file to your test project
    example: rake gen:test[describe_BlogsController]

rake gen:view[controller_and_view_name]
    adds a cshtml to your mvc project
    example: rake gen:view[Home:Index]

Sample Apps


Download the Source

These are the sample apps that show off all of Oak's capabilities. The sample apps (and there are alot of them) come with Oak's source:

You can download the source as a zip file which includes all of the sample apps from here (~73MB)

== OR ==

clone the git repo (~200MB):

git clone https://github.com/amirrajan/Oak.git

Some of the sample apps use additional ruby gems, run the folowing command to prep your system for these gems:

gem install bundler

Get VS 2013

All sample apps are written using VS 2013, install the express edition if needed (you can use Oak with VS 2010 and VS 2012, refer to the wiki for instructions).

Minimal Implementation: DynamicBlog

This blogging applications is will show you how to perform validation and data access using Oak's mixins. Look at the other sample apps for a deeper dive into Oak.

Hello World Single Page Apps: Peeps

This is a really simple app that adds and updates records to a single table over ajax. This sample app shows how Oak can easily integrate with a number of JavaScript frameworks such as:

For a more complex application that shows integration with JavaScript frameworks, you may want to look at the Task Rabbits sample app for a deeper dive.

Two Player Game, Complex Object Graph: BattleShip

This is a web based version of the game BattleShip. This sample app shows the use of a rich domain model that uses dynamic classes. There is also a supporting test suite that shows how to test ASP.NET MVC applications.

Single Page App, JS framework integration: Task Rabbits

This app show more complex usages of JavaScript frameworks and how they integrate with the server side. This sample app also comes with an UI automation suite, so you can see how to write UI automation tests for a more complex application. You can use this sample app to do a side by side comparison of the following JavaScript frameworks:

Single Page App, CoffeeScript, Complex DB Queries: Crib

This is a web application that tracks consultants and when they roll off of a client engagement. This sample app uses BackboneJS and CoffeeScript on the front end, again showing the integration with the server side. This application also shows how to do more complex data access using Oak's DynamicRepository. Integration/unit test suite included.

Single Page App, REST Api: Todo List

The app is a simple todo list that allows you to add items, remove them, and mark things as done. The front end is built using JavaScript and BackboneJS. The server side code shows a sample of how you can create a REST Api using ASP.NET MVC and the dynamic capabilities of Oak. There is a test suite associated with this app that shows how to test a REST Api too.

THE Reference App - Borrowed Games


This is a full blown reference implementation that uses all aspects of Oak. Borrowed Games is a single page web app that allows a circle of friends to borrow games from each other. The app's front end is written in BackboneJS and CoffeeScript. It comes with a full unit/integration test suite, along with UI Automation.

More Stuff