A simple SPA with AngularJs, ASP.NET MVC, Web API and EF

SPA stands for Single Page Application. Here I will demonstrate a simple SPA with ASP.NET MVC, Web API and Entity Framework. I will show a trainer profile and its CRUD operation using AngularJS, ASP.NET MVC, Web api and Entity Framework.

Step 1: Create a ASP.NET MVC application with empty template

Open visual studio, Got to File->New->Project
Select Template -> Visual C# -> Web -> ASP.NET MVC 4 Web application and click OK
Select Empty Template and Razor as view engine

Step 2: Install required packages
Run the following command in Package Manager Console (Tools->Library Package Manager->Package Manager Console) to install required package. Make sure your internet connection is enabled.

PM> Install-Package jQuery
PM> Install-Package angularjs -Version 1.2.26
PM> Install-Package Newtonsoft.Json
PM> Install-Package MvcScaffolding

Step 3: Create Connection String
Create connection string and name DB name as SPADB

  
    
  

Step 4: Create model

Create Trainer model

    public class Trainer
    {
        [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public long Id { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
        public string Venue { get; set; }
    }

Step 5: Create Repository
Create repository for Trainer model. Run the following command in Package Manager Console (Tools->Library Package Manager->Package Manager Console) to create repository. I used repository pattern for well-structured and more manageable.

PM> Scaffold Repository Trainer

After running the above command you will see SPAContext.cs and TrainerRepository.cs created in Model folder. For well manageability, I create a directory name Repository and put these two files in the Repository folder. So change the namespace as like SPA.Repository instead of SPA.Model. I also create a UnitOfWork for implement unit of work pattern.

The overall folder structure looks like following.

st-final

SPAContext.cs

    public class SPAContext : DbContext
    {
        public SPAContext()
            : base("SPAContext")
        {
        }
        // You can add custom code to this file. Changes will not be overwritten.
        // 
        // If you want Entity Framework to drop and regenerate your database
        // automatically whenever you change your model schema, add the following
        // code to the Application_Start method in your Global.asax file.
        // Note: this will destroy and re-create your database with every model change.
        // 
        // System.Data.Entity.Database.SetInitializer(new System.Data.Entity.DropCreateDatabaseIfModelChanges());

        public DbSet Trainers { get; set; }

        public DbSet Trainings { get; set; }
    }

TrainerRepository.cs

    public class TrainerRepository : ITrainerRepository
    {
        SPAContext context = new SPAContext();

        public TrainerRepository()
            : this(new SPAContext())
        {

        }
        public TrainerRepository(SPAContext context)
        {
            this.context = context;
        }


        public IQueryable All
        {
            get { return context.Trainers; }
        }

        public IQueryable AllIncluding(params Expression>[] includeProperties)
        {
            IQueryable query = context.Trainers;
            foreach (var includeProperty in includeProperties)
            {
                query = query.Include(includeProperty);
            }
            return query;
        }

        public Trainer Find(long id)
        {
            return context.Trainers.Find(id);
        }

        public void InsertOrUpdate(Trainer trainer)
        {
            if (trainer.Id == default(long))
            {
                // New entity
                context.Trainers.Add(trainer);
            }
            else
            {
                // Existing entity
                context.Entry(trainer).State = System.Data.Entity.EntityState.Modified;
            }
        }

        public void Delete(long id)
        {
            var trainer = context.Trainers.Find(id);
            context.Trainers.Remove(trainer);
        }

        public void Save()
        {
            context.SaveChanges();
        }

        public void Dispose()
        {
            context.Dispose();
        }
    }

    public interface ITrainerRepository : IDisposable
    {
        IQueryable All { get; }
        IQueryable AllIncluding(params Expression>[] includeProperties);
        Trainer Find(long id);
        void InsertOrUpdate(Trainer trainer);
        void Delete(long id);
        void Save();
    }

UnitOfWork.cs

    public class UnitOfWork : IDisposable
    {
        private SPAContext context;
        public UnitOfWork()
        {
            context = new SPAContext();
        }

        public UnitOfWork(SPAContext _context)
        {
            this.context = _context;
        }

        private TrainingRepository _trainingRepository;

        public TrainingRepository TrainingRepository
        {
            get
            {

                if (this._trainingRepository == null)
                {
                    this._trainingRepository = new TrainingRepository(context);
                }
                return _trainingRepository;
            }
        }


        private TrainerRepository _trainerRepository;

        public TrainerRepository TrainerRepository
        {
            get
            {

                if (this._trainerRepository == null)
                {
                    this._trainerRepository = new TrainerRepository(context);
                }
                return _trainerRepository;
            }
        }

        public void Dispose()
        {
            context.Dispose();
            GC.SuppressFinalize(this);
        }
    }

Step 6: Add migration

Run the following command to add migration
PM> Enable-Migrations
PM> Add-Migration initialmigration
PM> Update-Database –Verbose

Step 7: Create API Controllers
Create Trainers api Controllers by clicking right button on Controller folder and scaffold as follows.

TrainersController-2

Step 8: Modify Controllers

Now modify the controllers as follows. Here I used unit of work pattern.

    public class TrainersController : ApiController
    {
        private UnitOfWork unitOfWork = new UnitOfWork();

        public IEnumerable Get()
        {
            List lstTrainer = new List();
            lstTrainer = unitOfWork.TrainerRepository.All.ToList();
            return lstTrainer;
        }

        //// GET api/trainers/5
        public Trainer Get(int id)
        {
            Trainer objTrainer = unitOfWork.TrainerRepository.Find(id);
            return objTrainer;
        }

   
        public HttpResponseMessage Post(Trainer trainer)
        {

            if (ModelState.IsValid)
            {
                unitOfWork.TrainerRepository.InsertOrUpdate(trainer);
                unitOfWork.TrainerRepository.Save();
                return new HttpResponseMessage(HttpStatusCode.OK);
            }
            return new HttpResponseMessage(HttpStatusCode.InternalServerError);
        }


        private IEnumerable GetErrorMessages()
        {
            return ModelState.Values.SelectMany(x => x.Errors.Select(e => e.ErrorMessage));
        }

   

        // PUT api/trainers/5
        public HttpResponseMessage Put(int Id, Trainer trainer)
        {
            if (ModelState.IsValid)
            {
                unitOfWork.TrainerRepository.InsertOrUpdate(trainer);
                unitOfWork.TrainerRepository.Save();
                return new HttpResponseMessage(HttpStatusCode.OK);
            }
            else
                return new HttpResponseMessage(HttpStatusCode.InternalServerError);
        }

        // DELETE api/trainers/5
        public HttpResponseMessage Delete(int id)
        {
            Trainer objTrainer = unitOfWork.TrainerRepository.Find(id);
            if (objTrainer == null)
            {
                return new HttpResponseMessage(HttpStatusCode.InternalServerError);
            }

            unitOfWork.TrainerRepository.Delete(id);
            unitOfWork.TrainerRepository.Save();

            return new HttpResponseMessage(HttpStatusCode.OK);
        }
    }

Step 9: Create Layout and Home Controller
Create _Layout.cshtml in Views->Shared folder and create HomeController and create inext view of Home controller by right click on index action and add view. You will see index.cshtml is created in Views->Home

Home Controller

    public class HomeController : Controller
    {
        //
        // GET: /Home/

        public ActionResult Index()
        {
            return View();
        }

    }

_Layout.cshtml



    Training Registration



    @RenderBody()



Index.cshtml

@{
    ViewBag.Title = "Home";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

Home

Step 10: Create registrationModule

Create registrationModule.js in Scripts->Application. This is for angularjs routing.

var registrationModule = angular.module("registrationModule", ['ngRoute', 'ngResource'])
    .config(function ($routeProvider, $locationProvider) {

        $routeProvider.when('/Registration/Trainers', {
            templateUrl: '/templates/trainers/all.html',
            controller: 'listTrainersController'
        });

        $routeProvider.when('/Registration/Trainers/:id', {
            templateUrl: '/templates/trainers/edit.html',
            controller: 'editTrainersController'
        });

        $routeProvider.when('/Registration/Trainers/add', {
            templateUrl: '/templates/trainers/add.html',
            controller: 'addTrainersController'
        });

        $routeProvider.when("/Registration/Trainers/delete/:id", {
            controller: "deleteTrainersController",
            templateUrl: "/templates/trainers/delete.html"
        });

        $locationProvider.html5Mode(true);
    });

Step 11: Create trainerRepository

Create trainerRepository.js in Scripts->Application->Repository. This increase manageability for large application.

'use strict';

//Repository for trainer information
registrationModule.factory('trainerRepository', function ($resource) {

    return {
        get: function () {
            return $resource('/api/Trainers').query();
        },

        getById: function (id) {
            return $resource('/api/Trainers/:Id', { Id: id }).get();
        },

        save: function (trainer) {
            return $resource('/api/Trainers').save(trainer);
        },

        put: function (trainer) {
            return $resource('/api/Trainers', { Id: trainer.id },
                {
                    update: { method: 'PUT' }
                }).update(trainer);
        },

        remove: function (id) {
            return $resource('/api/Trainers').remove({ Id: id });
        }
    };

});

Step 12: Create trainerController

Create trainerController.js in Scripts->Application->Controllers

'use strict';

//Controller to get list of trainers informaion
registrationModule.controller("listTrainersController", function ($scope, trainerRepository, $location) {
    $scope.trainers = trainerRepository.get();
});


//Controller to save trainer information
registrationModule.controller("addTrainersController", function ($scope, trainerRepository, $location) {
    $scope.save = function (trainer) {
        trainer.Id = 0;
        $scope.errors = [];
        trainerRepository.save(trainer).$promise.then(
            function () { $location.url('Registration/Trainers'); },
            function (response) { $scope.errors = response.data; });
    };
});


//Controller to modify trainer information
registrationModule.controller("editTrainersController", function ($scope,$routeParams, trainerRepository, $location) {
    $scope.trainer = trainerRepository.getById($routeParams.id);

    $scope.update = function (trainer) {
        $scope.errors = [];
        trainerRepository.put(trainer).$promise.then(
            function () { $location.url('Registration/Trainers'); },
            function (response) { $scope.errors = response.data; });
    };
});

//Controller to delete trainer information
registrationModule.controller("deleteTrainersController", function ($scope, $routeParams, trainerRepository, $location) {
        trainerRepository.remove($routeParams.id).$promise.then(
            function () { $location.url('Registration/Trainers'); },
            function (response) { $scope.errors = response.data; });
});

Step 13: Create templates
Create all.html, add.html, edit.html, delete.html in templateds->trainers folder.

All.html

Trainers Details

Name Email Venue Action
{{trainer.name}} {{trainer.email}} {{trainer.venue}} Delete |Edit

Add.html

Trainer Name
Email
Venue
Cancel

Edit.html

Name
Email
Venue

Step 14: Add references to the Layout
Modify the _Layout.cshtml to add references

_Layout.cshtml





    Training Registration

    
    
    
    
    
    
    



    @RenderBody()



Now run you application and add, delete, modify and get all trainer information. Thanks for your patient!

[wpdm_file id=43]

4 thoughts on “A simple SPA with AngularJs, ASP.NET MVC, Web API and EF

Leave a Reply

Your email address will not be published. Required fields are marked *