Click here to Skip to main content
Click here to Skip to main content

Using AngularJs, ASP.NET MVC, Web API and EntityFramework to build NLayered Single Page Web Applications

, 17 Aug 2014
Rate this:
Please Sign up or sign in to vote.
Building an NLayered, localized, well-structured Single-Page Web Application using AngularJs, ASP.NET MVC, Web API, EntityFramework and ASP.NET Boilerplate.

Simple Task System Screenshot
A screenshot of the sample application.

Contents

Introduction

In this article, I'll show you how to develop a Single-Page Web Application (SPA) from ground to up using the following tools:

  • ASP.NET MVC and ASP.NET Web API as web framework.
  • Angularjs as SPA framework.
  • EntityFramework as ORM (Object-Relational Mapping) framework
  • Castle Windsor as Dependency Injection framework.
  • Twitter Bootstrap as HTML/CSS framework.
  • ASP.NET Boilerplate as startup template and application framework.
  • Log4Net for logging, AutoMapper for object-to-object mapping.

ASP.NET Boilerplate [1] is an open source project that combines all these frameworks/libraries to make you start easily to develop your application. It also provides us an infrastructure to develop applications in best practices. It naturally supports Dependency Injection, Domain Driven Design and Layered Architecture.

The sample application also implements validation, exception handling, localization and responsive design.

Create the application from boilerplate template

ASP.NET Boilerplate saves your time while starting a new application by providing templates that combines and configures best tools to build enterprise level web applications.

Let's go to aspnetboilerplate.com/Templates to build our application from template...

Create template by ASP.NET Boilerplate

Here, I selected Single Page Application with AngularJs and EntityFramework. Also entered SimpleTaskSystem for my project name. It created and downloaded my solution. I opened it in Visual Studio 2013:

Solution structure

There are 5 projects included to the solution. Core project for domain (business) layer, Application project for application layer, WebApi project to implement Web Api controllers, Web project for presentation layer and finally Infrastructure.EntityFramework project for EntityFramework implementation.

Create entities

I'm creating a simple application to create tasks and assing tasks to people. So, I need Task and Person entities.

Task entity simply defines a Description, CreationTime and State for a Task. It also has an optional reference to a Person (AssignedPerson):

public class Task : Entity<long>
{
    [ForeignKey("AssignedPersonId")]
    public virtual Person AssignedPerson { get; set; }

    public virtual int? AssignedPersonId { get; set; }

    public virtual string Description { get; set; }

    public virtual DateTime CreationTime { get; set; }

    public virtual TaskState State { get; set; }

    public Task()
    {
        CreationTime = DateTime.Now;
        State = TaskState.Active;
    }
}

Person entity is simpler and just defines Name of the person:

public class Person : Entity
{
    public virtual string Name { get; set; }
}

ASP.NET Boilerplate provides Entity classes that defines Id poperty. I derived entities from this Entity class. Task class has an Id of type long since I derived from Entity<long>. Person class has an Id of type int. Since int is the default primary key type, I did not specified it.

I defined entities in the Core project since Entities are parts of domain/business layer.

Create DbContext

As you know, EntityFramework works with DbContext class. We should first define it. ASP.NET Boilerplate template creates a DbContext template for us. I added IDbSets for Task and Person. I also made some configuration on OnModelCreating method. These configurations could be achived with data annotations on entities. I did not prefer it but you can do it in that way. This is my DbContext class:

public class SimpleTaskSystemDbContext : AbpDbContext
{
    public virtual IDbSet<Task> Tasks { get; set; }
    public virtual IDbSet<Person> People { get; set; }

    public SimpleTaskSystemDbContext()
        : base("MainDb")
    {

    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Person>().ToTable("StsPeople");
        modelBuilder.Entity<Task>().ToTable("StsTasks").HasOptional(t => t.AssignedPerson);
    }
}

It uses MainDb connection string in web.config. It's defined as shown below:

<add name="MainDb" connectionString="Server=localhost; Database=SimpleTaskSystemDb; Trusted_Connection=True;" providerName="System.Data.SqlClient" />

Create Database Migrations

We'll use EntityFramework's Code First Migrations to create and maintain the database schema. Open the Package Manager Console and type the following command (Default project must be set to SimpleTaskSystem.Infrastructure.EntityFramework in console window):

PM> Enable-Migrations

A screenshot from package manager console (Selecting default project):

Package manager console enable migrations

This will enable migrations for our DbContext (SimpleTaskSystemDbContext) and create a Configuration class as shown below:

internal sealed class Configuration : DbMigrationsConfiguration<SimpleTaskSystem.EntityFramework.SimpleTaskSystemDbContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
    }

    protected override void Seed(SimpleTaskSystem.EntityFramework.SimpleTaskSystemDbContext context)
    {
        context.People.AddOrUpdate(
            p => p.Name,
            new Person {Name = "Isaac Asimov"},
            new Person {Name = "Thomas More"},
            new Person {Name = "George Orwell"},
            new Person {Name = "Douglas Adams"}
            );
    }
}

In the Seed method, I added four people for initial data. Now, I'll create the initial migration:

PM> Add-Migration "InitialCreate"

This command creates a class named InitialCreate as shown below:

public partial class InitialCreate : DbMigration
{
    public override void Up()
    {
        CreateTable(
            "dbo.StsPeople",
            c => new
                {
                    Id = c.Int(nullable: false, identity: true),
                    Name = c.String(),
                })
            .PrimaryKey(t => t.Id);
            
        CreateTable(
            "dbo.StsTasks",
            c => new
                {
                    Id = c.Long(nullable: false, identity: true),
                    AssignedPersonId = c.Int(),
                    Description = c.String(),
                    CreationTime = c.DateTime(nullable: false),
                    State = c.Byte(nullable: false),
                })
            .PrimaryKey(t => t.Id)
            .ForeignKey("dbo.StsPeople", t => t.AssignedPersonId)
            .Index(t => t.AssignedPersonId);            
    }
        
    public override void Down()
    {
        DropForeignKey("dbo.StsTasks", "AssignedPersonId", "dbo.StsPeople");
        DropIndex("dbo.StsTasks", new[] { "AssignedPersonId" });
        DropTable("dbo.StsTasks");
        DropTable("dbo.StsPeople");
    }
}

We did create needed classes to create the database, but not created the database yet. To do it, I'll run the following command:

PM> Update-Database

This command runs the migrations, creates the database and populates the initial data for us:

Database created by EntityFramework Migrations

When we did changes on Entitiy classes, we can easily create a new migration class using Add-Migration command and update the database with Update-Database command. To learn more about database migrations, see entity framework's documentation.

Define repositories

In domain driven design, repositories used to implement database-specific codes. As I want to seperate interface from implementation, I declare interfaces for repositories first. Here, is the Task repository interface:

public interface ITaskRepository : IRepository<Task, long>
{
    List<Task> GetAllWithPeople(int? assignedPersonId, TaskState? state);
}

It extends generic IRepository interface of ASP.NET Boilerplate. IRepository defines common methods for select, insert, update, delete and a few more:

Generic IRepository interface

So, ITaskRepository inherently defines all these methods as default. It can also add it's own methods as I defined GetAllWithPeople(...). IPersonRepository is simpler, does not define any additional methods to IRepository:

public interface IPersonRepository : IRepository<Person>
{
}

I defined repositories in the Core project since they are parts of domain/business layer.

Implement repositories

We should implement the interfaces defined above. I'm implementing repositories in Infrastructure.EntityFramework project. Thus, domain layer becomes completely independent from EntityFramework.

When we created project template, ASP.NET Boilerplate defined a generic base class for repositories for our project: SimpleTaskSystemRepositoryBase. It's a good practice to have such a base class since we can later add some common methods for our repositories. You can see definition of this class in the code. I just derive from it for TaskRepository implementation:

public class TaskRepository : SimpleTaskSystemRepositoryBase<Task, long>, ITaskRepository
{
    public List<Task> GetAllWithPeople(int? assignedPersonId, TaskState? state)
    {
        var query = Context.Tasks.AsQueryable();
        //var query = GetAll(); //alternative shortcut
            
        if (assignedPersonId.HasValue)
        {
            query = query.Where(task => task.AssignedPerson.Id == assignedPersonId.Value);
        }

        if (state.HasValue)
        {
            query = query.Where(task => task.State == state);
        }

        return query
            .OrderByDescending(task => task.CreationTime)
            .Include(task => task.AssignedPerson)
            .ToList();
    }
}

TaskRepository is derived from SimpleTaskSystemRepositoryBase and implements ITaskRepository we defined above.

GetAllWithPeople is our specific method to get Tasks, where AssignedPerson included (pre-fetched) and optionally filtered by some conditions. In the first line, we're using Context.Tasks to reach the Tasks in DbContext. We can freely use it in repositories. ASP.NET Boilerplate manages database connection, database transaction, creating and disposing the DbContext for us (See documentation for more information)

Implementing PersonRepository is much simpler since it does not define any additional methods:

public class PersonRepository : SimpleTaskSystemRepositoryBase<Person>, IPersonRepository
{
}

Build application services

Application services is used to seperate presentation layer from domain layer by providing façade style methods. I define application services in the Application assembly in the project. First, I define interface for task application service:

public interface ITaskAppService : IApplicationService
{
    GetTasksOutput GetTasks(GetTasksInput input);
    void UpdateTask(UpdateTaskInput input);
    void CreateTask(CreateTaskInput input);
}

ITaskAppService extends IApplicationService. Thus, ASP.NET Boilerplate automatically provides some features for this class (like dependency injection and validation). Now, let's implement ITaskAppService:

public class TaskAppService : ITaskAppService
{
    public ILogger Logger { get; set; }

    private readonly ITaskRepository _taskRepository;
    private readonly IPersonRepository _personRepository;

    public TaskAppService(ITaskRepository taskRepository, IPersonRepository personRepository)
    {
        _taskRepository = taskRepository;
        _personRepository = personRepository;
        Logger = NullLogger.Instance;
    }

    public GetTasksOutput GetTasks(GetTasksInput input)
    {
        var tasks = _taskRepository.GetAllWithPeople(input.AssignedPersonId, input.State);
        return new GetTasksOutput
                {
                    Tasks = Mapper.Map<List<TaskDto>>(tasks)
                };
    }

    public void UpdateTask(UpdateTaskInput input)
    {
        Logger.Info("Updating a task for input: " + input);

        var task = _taskRepository.Get(input.TaskId);

        if (input.State.HasValue)
        {
            task.State = input.State.Value;
        }

        if (input.AssignedPersonId.HasValue)
        {
            task.AssignedPerson = _personRepository.Load(input.AssignedPersonId.Value);
        }
    }

    public void CreateTask(CreateTaskInput input)
    {
        var task = new Task { Description = input.Description };

        if (input.AssignedPersonId.HasValue)
        {
            task.AssignedPersonId = input.AssignedPersonId.Value;
        }

        _taskRepository.Insert(task);
    }
}

TaskAppService uses repositories for database operations. It gets references in it's constructor via constructor injection pattern. It also gets Logger using property injection. ASP.NET Boilerplate naturally implements dependency injection, so we can use constructor injection or property injection freely (See more on dependency injection in ASP.NET Boilerplate documentation).

Application service methods works with Data Transfer Objects (DTOs). It's a best practice and I definitely suggest to use this pattern. But you don't have to do it as long as you can deal with problems of exposing Entities to presentation layer.

In the GetTasks method, I used the GetAllWithPeople method that I implemented before. It returns a List<Task> but I need to return a List<TaskDto> to presentation layer. AutoMapper helps us here to automatically convert Task objects to TaskDto objects. GetTasksInput and GetTasksOutput are special DTOs defined for GetTasks method.

In the UpdateTask method, I retrived the Task from database (using IRepository's Get method) and changed peoperties of the Task. Notice that I did not even called Update method of the repository. ASP.NET Boilerplate implements UnitOfWork pattern. So, all changes in an application service method are a unit of work (atomic) and applied to database at the end of the method automatically.

In the CreateTask method, I simply created a new Task and inserted to database using the IRepository's Insert method.

ASP.NET Boilerplate has also an ApplicationService class. It has some properties to make developing application service easier. For example, it defines a Logger property for logging. So, we could derive TaskAppService from ApplicationService and use this Logger property instead of property injection as I did here.

Validation

ASP.NET Boilerplate automatically validates inputs of application service methods if method's parameter implements IInputDto (or directly IValidate).

CreateTask method gets CreateTaskInput as parameter:

public class CreateTaskInput : IInputDto
{
    public int? AssignedPersonId { get; set; }

    [Required]
    public string Description { get; set; }
}

Here, Description is marked as Required. You can use any Data Annotation attributes here. If you want to make some custom validation, you can implement ICustomValidate as I implemented in UpdateTaskInput:

public class UpdateTaskInput : IInputDto, ICustomValidate
{
    [Range(1, long.MaxValue)]
    public long TaskId { get; set; }

    public int? AssignedPersonId { get; set; }

    public TaskState? State { get; set; }

    public void AddValidationErrors(List<ValidationResult> results)
    {
        if (AssignedPersonId == null && State == null)
        {
            results.Add(new ValidationResult("Both of AssignedPersonId and State can not be null in order to update a Task!", new[] { "AssignedPersonId", "State" }));
        }
    }

    public override string ToString()
    {
        return string.Format("[UpdateTask > TaskId = {0}, AssignedPersonId = {1}, State = {2}]", TaskId, AssignedPersonId, State);
    }
}

AddValidationErrors method is the place you can write your custom validation code.

Handling exceptions

Note that we did not handled any exception. ASP.NET Boilerplate automatically handles exceptions, logs and returns an appropriate error message to the client. Also, in client side, handles these error messages and show to the user. Actually, this is true for ASP.NET MVC and Web API Controller actions. Since we will expose the TaskAppService using Web API, we don't need to handle exceptions. See exception handling document for details.

Build Web API services

I want to expose my application services to remote clients. Thus, my AngularJs application can easily call these service methods using AJAX.

ASP.NET Boilerplate provides an automatic way of exposing desired application service methods as ASP.NET Web API. I just use DynamicApiControllerBuilder as shown below:

DynamicApiControllerBuilder
    .For<ITaskAppService>("tasksystem/task")
    .Build();

DynamicApiControllerBuilder
    .For<IPersonAppService>("tasksystem/person")
    .Build();

We'll see how to call these services via AJAX.

Develop the SPA

I'll implement a Single-Page Web Application for user interface of my project. AngularJs (by Google) is one (propably the top one) of the most used SPA frameworks.

ASP.NET Boilerplate provides a template that makes easy to start with AngularJs. The template has two pages (Home and About) with smooth transition between pages. Uses Twitter Bootstrap as HTML/CSS framework (thus, it's responsive). It's also localized into English and Turkish with ASP.NET Boilerplate's localization system (You can easly add other languages or remove one of them).

We first change route of template. AngularJs provides a strong rotuing to map URLs to views. We will have two views: task list and new task. So, we will change route definition in app.js as shown below:

app.constant('routes', [
    {
        url: '/',
        config: {
            templateUrl: '/App/Main/views/task/list.cshtml',
            menuText: localize('TaskList'),
            menuItem: 'TaskList'
        }
    },
    {
        url: '/new',
        config: {
            templateUrl: '/App/Main/views/task/new.cshtml',
            menuText: localize('NewTask'),
            menuItem: 'NewTask'
        }
    }
]);

app.js is the main javascript file to configure and start our SPA. Notice that we're using cshtml files as views! Normally, html files are used as views in AngularJs. ASP.NET Boilerplate makes it possible to use cshtml files. Thus we will have the power of razor engine to generate HTML.

layout.cshtml understands this route configuration and generates the top menu. So, when you add a new route, it will apper in the top menu automatically. See it's source for details.

First, I'm creating the controller for the task list view:

(function() {
    var app = angular.module('app');

    var controllerId = 'sts.controllers.views.task.list';
    app.controller(controllerId, [
        '$scope', 'abp.services.tasksystem.task',
        function($scope, taskService) {
            var vm = this;

            vm.localize = abp.localization.getSource('SimpleTaskSystem');

            vm.tasks = [];

            $scope.selectedTaskState = 0;

            $scope.$watch('selectedTaskState', function(value) {
                vm.refreshTasks();
            });

            vm.refreshTasks = function() {
                taskService.getTasks({
                    state: $scope.selectedTaskState > 0 ? $scope.selectedTaskState : null
                }).success(function(data) {
                    vm.tasks = data.tasks;
                });
            };

            vm.changeTaskState = function(task) {
                var newState;
                if (task.state == 1) {
                    newState = 2; //Completed
                } else {
                    newState = 1; //Active
                }

                taskService.updateTask({
                    taskId: task.id,
                    state: newState
                }).success(function() {
                    task.state = newState;
                    abp.notify.info(vm.localize('TaskUpdatedMessage'));
                });
            };

            vm.getTaskCountText = function() {
                return abp.utils.formatString(vm.localize('Xtasks'), vm.tasks.length);
            };
        }
    ]);
})();

I defined name of the controller as 'sts.controllers.views.task.list'. This my convention (for scalable code-base) but you can simply name it as 'ListController'. AngularJs also uses dependency injection. We're injecting '$scope' and 'abp.services.tasksystem.task' here. First one is Angular's scope variable, second one is the automatically created javascript service proxy for ITaskAppService (we built it before in 'Build Web API services' section).

ASP.NET Boilerplate provides infrastructure to use same localization texts both in server and client (see it's documentation for details). 

vm.taks is the list of tasks that will be shown in the view. vm.refreshTasks method fills this array by getting tasks using taskService. It's called when selectedTaskState changes (observed using $scope.$watch).

As you see, calling an application service method is very easy and straightforward! This is a feature of ASP.NET Boilerplate. It generates Web API layer and Javascript proxy layer that talks with this Web API layer. Thus, we are calling the application service method as calling a simple javascript method. It is completely integrated with AngularJs (uses Angular's $http service).

Let's see the view side of task list:

<div class="panel panel-default" ng-controller="sts.controllers.views.task.list as vm">

    <div class="panel-heading" style="position: relative;">
        <div class="row">
            
            <!-- Title -->
            <h3 class="panel-title col-xs-6">
                @L("TaskList") - <span>{{vm.getTaskCountText()}}</span>
            </h3>
            
            <!-- Task state combobox -->
            <div class="col-xs-6 text-right">
                <select ng-model="selectedTaskState">
                    <option value="0">@L("AllTasks")</option>
                    <option value="1">@L("ActiveTasks")</option>
                    <option value="2">@L("CompletedTasks")</option>
                </select>
            </div>
        </div>
    </div>

    <!-- Task list -->
    <ul class="list-group" ng-repeat="task in vm.tasks">
        <div class="list-group-item">
            <span class="task-state-icon glyphicon" ng-click="vm.changeTaskState(task)" ng-class="{'glyphicon-minus': task.state == 1, 'glyphicon-ok': task.state == 2}"></span>
            <span ng-class="{'task-description-active': task.state == 1, 'task-description-completed': task.state == 2 }">{{task.description}}</span>
            <br />
            <span ng-show="task.assignedPersonId > 0">
                <span class="task-assignedto">{{task.assignedPersonName}}</span>
            </span>
            <span class="task-creationtime">{{task.creationTime}}</span>
        </div>
    </ul>

</div>

ng-controller attribute (in the first line) binds the controller to the view. @L("TaskList") gets localized text for "task list" (works on server while rendering HTML). It's possible since this is a cshtml file.

ng-model binds combobox and the javascript variable. When the variable changes, the combobox updated. When the combobox changes, the valiable is updated. This is two-way binding of AngularJs.

ng-repeat is another 'directive' of Angular that is used to render same HTML for each value in an array. When the array changes (an item is added for example), it's automatically reflected to the view. This is another powerful feature of AngularJs.

Note: When you add a javascript file (for example, for the 'task list' controller), you should add it to your page. This can be done by adding it to Home\Index.cshtml in the template.

Localization

ASP.NET Boilerplate provides a flexible and strong localization system. You can use XML files or Resource files as localization source. You can also define custom localization sources. See documentation for more. In this sample application, I used XML files (it's under Localization folder in web application):

<?xml version="1.0" encoding="utf-8" ?>
<localizationDictionary culture="en">
  <texts>
    <text name="TaskSystem" value="Task System" />
    <text name="TaskList" value="Task List" />
    <text name="NewTask" value="New Task" />
    <text name="Xtasks" value="{0} tasks" />
    <text name="AllTasks" value="All tasks" />
    <text name="ActiveTasks" value="Active tasks" />
    <text name="CompletedTasks" value="Completed tasks" />
    <text name="TaskDescription" value="Task description" />
    <text name="EnterDescriptionHere" value="Task description" />
    <text name="AssignTo" value="Assign to" />
    <text name="SelectPerson" value="Select person" />
    <text name="CreateTheTask" value="Create the task" />
    <text name="TaskUpdatedMessage" value="Task has been successfully updated." />
    <text name="TaskCreatedMessage" value="Task {0} has been created successfully." />
  </texts>
</localizationDictionary>

Summary

In this article, I demonstrated how to develop an NLayered ASP.NET MVC web application with a SPA and responsive user interface. I used ASP.NET Boilerplate since it makes easy to develop such applications using best practices and saves our time.

I did write an article "Introduction to ASP.NET Boilerplate" that explains ASP.NET Boilerplate in more deep. Also, you can check the documentation for more information. Finally, you can get source codes on github repository. If you want to be informed about ASP.NET Boilerplate, follow @aspboilerplate on twitter.

Article history

  • 17.08.2014: Updated sample project to ABP v0.3.1.2.
  • 22.07.2014: Updated sample project to ABP v0.3.0.1.
  • 11.07.2014: Added screenshot of 'Enable-Migrations' command.
  • 08.07.2014: Updated sample project and article.
  • 01.07.2014: First publish of the article.

References

[1] ASP.NET Boilerplate official website: http://www.aspnetboilerplate.com

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Halil ibrahim Kalkan
Software Developer Sestek
Turkey Turkey
I have started programming at 14 years old using Pascal as hobby. Then I interested in web development (HTML, JavaScript, ASP...) before university.
 
I graduated from Sakarya University Computer Engineering. At university, I learned C++, Visual Basic.NET, C#, ASP.NET and Java. I partly implemented ARP, IP and TCP protocols in Java as my final term project.
 
Now, I am working in a private company in Istanbul as a senior software architect & developer. Working on Windows and web based software development using C# and ASP.NET MVC.
 
http://www.halilibrahimkalkan.com
Follow on   Twitter   LinkedIn

Comments and Discussions

 
QuestionException Details Pinmembertcollett16-Aug-14 20:25 
AnswerRe: Exception Details PinpremiumHalil ibrahim Kalkan17-Aug-14 1:54 
GeneralMy vote of 5 PinprofessionalMihai MOGA13-Aug-14 1:44 
GeneralRe: My vote of 5 PinpremiumHalil ibrahim Kalkan13-Aug-14 1:48 
QuestionIssue passing "GetTasksInput" object from angular to GetTasks Method PinmemberMember 311507110-Aug-14 23:50 
AnswerRe: Issue passing "GetTasksInput" object from angular to GetTasks Method PinpremiumHalil ibrahim Kalkan11-Aug-14 2:45 
GeneralRe: Issue passing "GetTasksInput" object from angular to GetTasks Method PinmemberMember 311507111-Aug-14 4:16 
Questioninjector Pinmemberron012345-Aug-14 21:03 
AnswerRe: injector PinpremiumHalil ibrahim Kalkan10-Aug-14 0:05 
QuestionASP.Net Identity 2 missed PinmemberMalik M. Hashim3-Aug-14 8:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140814.1 | Last Updated 17 Aug 2014
Article Copyright 2014 by Halil ibrahim Kalkan
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid