DotNetCurry Logo

Using ASP.NET 5, Angular.js and Entity Framework 7 Beta for building a Business Application

Posted by: Mahesh Sabnis , on 2/16/2015, in Category ASP.NET MVC
Views: 33821
Abstract: Visual Studio 2015 with Unified ASP.NET 5 provides some handy features for developing business applications. This article demoes an end-to-end app built using Visual Studio 2015 Preview.

Visual Studio 2015 Preview comes with new ASP.NET 5 templates for application development. If you haven’t used these templates earlier, check out my previous article Unified ASP.NET 5 - Using MVC 6, WEB API and Entity Framework 7 in an Application. The new templates come with many enhancements including Project.json where we can specify project dependencies, and config.json to define application level information e.g. Database connection string etc.

In this article, we will be using ASP.NET 5 for developing a business application which will make use of SQL Server Database, EntityFramework 7.0.0 beta, Angular.js, etc.

The scenario discussed in this application is of a simple Visitor Management System, which is used at the security gates of various IT companies. We will build a single page application (SPA) where visitors’ entries are maintained.

 

Section 1: Database design for the application

We will start with designing the database for the application. Since the application is for Visitor Management, we need Departments, Employees and Visitors tables. We will be creating a database using Sql Server 2012 with the following table scripts.

DepartmentMaster

CREATE TABLE [dbo].[DepartmentMaster] (
    [DeptNo]   INT          IDENTITY (1, 1) NOT NULL,
    [DeptName] VARCHAR (50) NOT NULL,
    PRIMARY KEY CLUSTERED ([DeptNo] ASC)
);

Employee

CREATE TABLE [dbo].[Employee] (
    [EmpNo]     INT          IDENTITY (1, 1) NOT NULL,
    [EmpName]   VARCHAR (50) NOT NULL,
    [ContactNo] VARCHAR (15) NOT NULL,
    [PhoneNo]   VARCHAR (10) NOT NULL,
    [Extension] VARCHAR (6)  NOT NULL,
    [DeptNo]    INT          NOT NULL,
    PRIMARY KEY CLUSTERED ([EmpNo] ASC),
    FOREIGN KEY ([DeptNo]) REFERENCES [dbo].[DepartmentMaster] ([DeptNo])
);

Visitor

CREATE TABLE [dbo].[Visitor] (
    [VisitorId]    INT           IDENTITY (1, 1) NOT NULL,
    [VisitorName]  VARCHAR (50)  NOT NULL,
    [ContactNo]    VARCHAR (15)  NOT NULL,
    [Organization] VARCHAR (50)  NOT NULL,
    [Address]      VARCHAR (100) NOT NULL,
    [City]         VARCHAR (50)  NOT NULL,
    [Purpose]      VARCHAR (50)  NOT NULL,
    [VisitDate]    DATETIME      NOT NULL,
    [EmpNo]        INT           NOT NULL,
    PRIMARY KEY CLUSTERED ([VisitorId] ASC),
    FOREIGN KEY ([EmpNo]) REFERENCES [dbo].[Employee] ([EmpNo])
);

Section 2: Creating ASP.NET 5 Application using Visual Studio 2015 Preview

In this section we will create an ASP.NET 5 Application. The Visual Studio 2015 Preview provides template for creating ASP.NET 5 Application with the following templates:

aspnet5-template

We will be selecting ASP.NET 5 Empty project template for our example. The project structure of the ASP.NET 5 Empty template is as follows:

project-structure

The wwwroot folder contains assemblies and packages to be deployed. The Dependencies folder contains the project dependencies. We will use it later in one of the steps. In this project, add folders of name Models, Views and Controllers.

Step 1: Since we need to make use of EntityFramework 7.0.0-beta, MVC 6, Razor, Routing and Angular.js in our project, we need to add the necessary references as dependencies. We can define these dependencies using project.json file. Open this file and add the required dependencies in it.

"dependencies": {
    "Microsoft.AspNet.Server.IIS": "1.0.0-beta1",
    "EntityFramework": "7.0.0-beta1",
    "EntityFramework.Commands": "7.0.0-beta1",
    "EntityFramework.SqlServer": "7.0.0-beta1",
    "EntityFramework.Migrations": "7.0.0-beta1",
    "Microsoft.AspNet.Mvc": "6.0.0-beta1",
    "Microsoft.Framework.ConfigurationModel.Json": "1.0.0-beta1",
    "Microsoft.AspNet.Diagnostics": "1.0.0-beta1",
    "Microsoft.AspNet.Mvc.Razor": "6.0.0-beta1",
    "Microsoft.AspNet.Routing": "1.0.0-beta1",
    "angularjs": "1.3.8.0"
},

We have to make use of Angular.js framework in the application and hence we need to define tasks for deploying the necessary files in the project. In VS 2015 Preview, we have default integration with the Grunt JavaScript library for managing client-side script task. If you are new to Grunt, read Using Grunt.js to Merge and Minify JavaScript files in an ASP.NET MVC Application. VS 2015 preview also provides integration with Bower, a package manager for the web. This is used to manage all dependencies required by the app e.g. Libraries, Frameworks, utilities, etc. Bower takes care of searching, downloading and saving necessary dependencies used by the web application. Since in our project, we require Angular.js Frameworks to be used and deployed, we require the Bower package manager. Hence we need to configure the installation of Bower using Grunt, in project.json. Add the following Script section in the project.json file.

"scripts": {
    "postrestore": [ "npm install" ],
    "prepare": [ "grunt bower:install" ]
}

Step 2: In the project, add Bower JSON Configuration File and Grunt Configuration file, as shown in the screenshot below.

bowergrunt

Open bower.json and specify the Angular.js Framework information with version no.

{
    "name": "A5_Biz_App",
    "private": true,
    "dependencies": {
        "angularjs": "1.3.8"
    },
    "exportsOverride": {
        "angularjs": {
            "js": "angular.{js,min.js,.min.js.map}"
        }
    }
}

Open Gruntfile.js and write logic for installing bower. This will install bower and add the framework specified by bower in the wwwroot/lib directory.

module.exports = function (grunt) {
    grunt.initConfig({
        bower: {
            install: {
                options: {
                    targetDir: "wwwroot/lib",
                    layout: "byComponent",
                    cleanTargetDir: false
                }
            } 
        } 
        
    });

    // This command registers the default task which will install bower packages into wwwroot/lib
    grunt.registerTask("default", ["bower:install"]);

    // The following line loads the grunt plugins.
    // This line needs to be at the end of this this file.
    grunt.loadNpmTasks("grunt-bower-task");
};

In step 1 and 2, we have initialized the basic dependencies for the application. Now it’s time for working with the models, views, etc.

Step 3: Open Config.json and add the Connection String of the database in it:

{
    "Data": {
        "DefaultConnection": { 
            "ConnectionString": "Data Source=.;Initial Catalog=Visitors;Integrated Security=SSPI"
        }
    }
}

Step 4: In the Models folder, add a new class file of name ModelRepository.cs. This file will contain classes mapped with the Database tables created in Section 1.

using System;
using Microsoft.Data.Entity.Metadata;
using Microsoft.Data.Entity;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Collections.Generic;

namespace A5_Biz_App.Models
{
    [Table("DepartmentMaster")]
    public class DepartmentMaster
    {
        [Key]
        public int DeptNo { get; set; }
        public string DeptName { get; set; }
        public virtual ICollection<Employee> Employees { get; set; }
    }

    [Table("Employee")]
    public class Employee
    {
        [Key]
        public int EmpNo { get; set; }
        public string EmpName { get; set; }
        public string ContactNo { get; set; }
        public string PhoneNo { get; set; }
        public string Extension { get; set; }
        public int DeptNo { get; set; }

        public virtual DepartmentMaster Department { get; set; }
    }

    [Table("Visitor")]
    public class Visitor
    {
        [Key]
        public int VisitorId { get; set; }
        public string VisitorName { get; set; }
        public string ContactNo { get; set; }
        public string Organization { get; set; }
        public string Address { get; set; }
        public string City { get; set; }
        public string Purpose { get; set; }
        public DateTime VisitDate { get; set; }
        public int EmpNo { get; set; }

        public virtual Employee  Employee { get; set; }
    }

    public class VisitorContext : DbContext
    {
        public DbSet<DepartmentMaster> Departments { get; set; }
        public DbSet<Employee> Employees { get; set; }
        public DbSet<Visitor> Visitors { get; set; }

        protected override void OnConfiguring(DbContextOptions options)
        {
            options.UseSqlServer(Startup.Configuration.Get("Data:DefaultConnection:ConnectionString"));
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<DepartmentMaster>().Key(x => x.DeptNo);
            modelBuilder.Entity<Employee>().Key(x => x.EmpNo);
            modelBuilder.Entity<Visitor>().Key(x => x.VisitorId);
        }
    }

}

We have DepartmentMaster, Employee and Visitor classes mapped with corresponding Tables in the ‘Visitors’ Database. The VisitorContext class connects to the Sql Server database using OnConfiguring method. The DbContextOptions object passed to this method contains UseSqlServer() method. This method reads connection string from the Config.json. The OnModelCreating() method class is used to define mapping between model classes corresponding to the Database tables.

Step 5: Since we have a relationship between DepartmentMaster-to-Employee and Employee-to-Visitor, we need to create View Model classes to read data from multiple models with relation. To do this in the Models folder, add a new class file of name ViewModels.cs with the following code:

using System;

namespace A5_Biz_App.Models
{
    public class DepartmentViewModel
    {
        public int DeptNo { get; set; }
        public string DeptName { get; set; }
    }

    public class EmployeeViewModel
    {
        public int EmpNo { get; set; }
        public string EmpName { get; set; }
        public string ContactNo { get; set; }
        public string PhoneNo { get; set; }
        public string Extension { get; set; }
    }
}

Step 6: We are building this application using Unified ASP.NET 5, which includes MVC 6 and WEB API. We need to specify in ASP.NET 5 the use of MVC 6 Framework and routing. To do so, we need to add some code in the Startup.cs.

using Microsoft.AspNet.Builder;
using Microsoft.Framework.ConfigurationModel;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Routing;
using Microsoft.Framework.DependencyInjection;
using A5_Biz_App.Models;

namespace A5_Biz_App
{
    public class Startup
    {

        public static IConfiguration Configuration { get; set; }
        public Startup(IHostingEnvironment env)
        {
            Configuration = new Configuration().AddJsonFile("Config.json").AddEnvironmentVariables();
        }

        /// <summary>
        /// Define the use of EntityFramework and use of MVC
        /// </summary>
        /// <param name="services"></param>
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddEntityFramework().AddSqlServer().AddDbContext<VisitorContext>();
            services.AddMvc();
        }

        /// <summary>
        /// Define Routing
        /// </summary>
        /// <param name="app"></param>
        public void Configure(IApplicationBuilder app)
        {
            app.UseMvc(r => r.MapRoute(
                name: "default",
                template: "{controller}/{action}/{id?}",
                defaults: new { controller = "Visitors", action = "Index" }));
            

        }
    }
}

The ConfigurationServices() method has IServiceCollection interface. This is used to inject dependency in the project. In the current application, we are using EntityFramework 7.0.0-beta which is defined using AddEntityFramework() method of IServiceCollection. The AddMvc () method indicates the use of MVC 6 for the application.

The Configure () method defines routing used for MVC.

Step 7: In the Controllers folder of the project, add a new WEB API Controller class of name ManageVisitorsAPIController. In this class, add method for reading Departments, Employees, and Visitors and also add method for Posting Visit.

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Mvc;
using A5_Biz_App.Models;

 
namespace A5_Biz_App.Controllers.Controllers
{
    [Route("api/ManageVisitorsAPI")]
    public class ManageVisitorsAPIController : Controller
    {
        VisitorContext ctx;
        public ManageVisitorsAPIController(VisitorContext c)
        {
            ctx = c;
        }

        // GET: api/values
        [HttpGet("Departments")]
        public IEnumerable<DepartmentViewModel> Get()
        {
            var Depts = from d in ctx.Departments
                        select new DepartmentViewModel()
                        {
                            DeptNo = d.DeptNo,
                            DeptName = d.DeptName
                        };

            return Depts.ToList() ;
        }


        [HttpGet("Employees/{dno}")]
        public IEnumerable<EmployeeViewModel> GetEmps(int dno)
        {
            List<EmployeeViewModel> Emps = new List<EmployeeViewModel>();
            Emps = (from e in ctx.Employees
                    where e.DeptNo == dno
                    select new EmployeeViewModel()
                    {
                        EmpNo = e.EmpNo,
                        EmpName = e.EmpName,
                        ContactNo = e.ContactNo,
                        PhoneNo = e.PhoneNo,
                        Extension = e.Extension
                    }).ToList();
            return Emps;
        }

        [HttpGet("Visitors/{id}")]
        public List<Visitor> GetVisitors(int id)
        {
            var visotors = (from v in ctx.Visitors
                            where v.EmpNo == id
                            select v).ToList();
            return visotors;
        }

        // POST api/values
         [HttpPost]
        public Visitor Post([FromBody]Visitor visitor)
        {
            ctx.Visitors.Add(visitor);
            ctx.SaveChanges();
            return visitor;
        }

    }
}

Each action method is defined with routing expression so that it can be accessed using Http. In the Controllers folder, add a new MVC Controller class of name VisitorsController. In the Views folder, add a new Subfolder of name Visitors in this folder and add a new View of name Index.cshtml. We will add UI elements in the view later.

Step 8: In the Visual Studio 2015 Preview, navigate to the View menu > Other Windows > Task Runner Explorer as shown below:

taskrunner

This will show Grunt tasks:

taskrunnerexp

In the Tasks > bower, right click on install and select Run:

grunt-task

This will show the packages copied in the wwwroot/lib folder:

taskrunres

The Angular.js installation can be seen with changed project structure:

project-structure-angular

The wwwroot folder now shows the bin folder with AspNet.Loader.dll assembly and the lib folder with angular.js files in it. So finally we got the deployable directory. Now it’s time for us to define client-side logic.

Step 9: In the wwwroot/lib/angularjs/js folder, add JavaScript files for the client-Side logic.

app.js

var app;
(function () {
    app = angular.module("bizModule", []);
})();

Above is the Angular Module, an entry point for the application.

Service.js

/// <reference path="~/lib/angularjs/js/angular.min.js" />
/// <reference path="app.js" />


app.service('bizService', function ($http) {


    //Create new record
    this.post = function (visitor) {
        var request = $http({
            method: "post",
            url: "/api/ManageVisitorsAPI",
            headers: { 'Content-Type': 'application/json;charset=utf-8' },
            data:visitor
        });
         
        return request;
    }
    //Get Visitors Records based on EmpNo
    this.getVisitors = function (EmpNo) {
        return $http.get("/api/ManageVisitorsAPI/Visitors/" + EmpNo);
    }

    //Get All Employees
    this.getEmployees = function (dno) {
        return $http.get("/api/ManageVisitorsAPI/Employees/" + dno);
    }

    //Get All Departments
    this.getDepartments = function () {
        return $http.get("/api/ManageVisitorsAPI/Departments");
    }
});

The service.js contains methods to encapsulate Ajax calls to WEB API. These method are used to perform GET operations on Departments, Employees, Visitors and post method for Visitors.

controller.js

/// <reference path="~/lib/angularjs/js/angular.min.js" />
/// <reference path="service.js" />

app.controller('bizController', function ($scope, $http, bizService) {

    ////The Default Department
    $scope.Department = {
        DeptNo: 0,
        DeptName:''
    };

    $scope.Employee = {
        EmpNo: 0,
        EmpName: '',
        PhoneNo: '',
        Extension:''
    };

    var d = new Date();
    $scope.date = d;

    loadDepartments();
    
    //Function to Load Departments
    function loadDepartments()
    {
        //Get Departments
        var promiseGetDepartments = bizService.getDepartments(); //The method from service

        promiseGetDepartments.then(function (d) {
            $scope.Departments = d.data;
        },function (err) {
                $scope.status = "Unable to load department";
       });

    }

    //Function to load employees
    $scope.loadEmployees = function () {
        var dno = $scope.Department.DeptNo;
        //Get Employees when the Call to Department Successdes
        var promisegetemployees = bizService.getEmployees(dno); //the method from service

        promisegetemployees.then(function (d) { $scope.Employees = d.data; },
            function (err) {
                $scope.status = "unable to load employees";
            });
    }
     


    //Function to get the selected Employee Details

    $scope.getEmployeeDetails = function (){
        $scope.ContactNoEmp = $scope.Employee.ContactNo;
        $scope.EmpNo = $scope.Employee.EmpNo;
    }

    //Function  to Save Visit

    $scope.save = function () {

       var visitor = {};
       visitor.VisitorName = $scope.VisitorName;
       visitor.ContactNo = $scope.ContactNo;
       visitor.Organization = $scope.Organization;
       visitor.Address = $scope.Address;
       visitor.City = $scope.City;
       visitor.Purpose = $scope.Purpose;
       visitor.VisitDate = new Date();
       visitor.EmpNo = $scope.EmpNo;

        var promisePost = bizService.post(visitor);

        promisePost.then(function (d) {
            $scope.VisitorId = d.data.VisitorId;
            
            $scope.status = "Visit is Saved";
        }, function (err) {
            $scope.status = "There is error";
        });
    }
});

The above controller contains method for retrieving Departments and Employees information, using loadDepartments() and loadEmployees() methods. The Save() method gets visitors information from the View.

Step 10: Open Index.cshtml and add the HTML markup and the Angular.js DataBinding in it:

<html ng-app="bizModule">
<head>
    <title>Biz App</title>
    <style type="text/css">
        table {
            width: 900px;
            border: medium;
        }

        td {
            border: thin;
        }

        .c1 {
            width: 300px;
        }
        .dv{
            border:medium;
            width:500px;
        }
        body{
            background-color:darkorange;
        }
    </style>
   
</head>

<body ng-controller="bizController">
    <h1>Visitor Management System</h1>
    <div>
        <span>Date:{{date | date:'dd-MM-yyyy'}}</span>
    </div>
    <table>

        <tr>
            <td>
                Visitor id:
            </td>
            <td>
                <input type="text" id="visitorid" ng-model="VisitorId" readonly="readonly" />
            </td>
        </tr>
        <tr>
            <td class="c1">Visitor Name:</td>
            <td>
                <input type="text" id="visitorname" ng-model="VisitorName" />
            </td>
            <td></td>
            <td class="c1">
                Mobile No:
            </td>
            <td>
                <input type="text" id="visitorcontactno" ng-model="ContactNo" />
            </td>
        </tr>

        <tr>
            <td class="c1">Address:</td>
            <td>
                <input type="text" id="visitoraddress" ng-model="Address" />
            </td>
            <td></td>
            <td class="c1">
                Company From:
            </td>
            <td>
                <input type="text" id="visitorcompany" ng-model="Organization" />
            </td>
        </tr>
        <tr>
            <td class="c1">City:</td>
            <td>
                <input type="text" id="visitorcity" ng-model="City" />
            </td>
            <td></td>
            <td class="c1">
                Purpose:
            </td>
            <td>
                <textarea id="visitorcontactno" ng-model="Purpose"></textarea>
            </td>
        </tr>
        <tr></tr>
    </table>
    <hr />
    <table style="width:800px">
        <tr>
            <td class="c1">
                Department:
            </td>
            <td>
                <select id="lstdept" ng-model="Department" ng-init="Department.DeptName"
                        ng-options="dept as dept.DeptName for dept in Departments"
                        ng-change="loadEmployees()"></select>
            </td>
            <td class="c1">
                Employee Name:
            </td>
            <td>
                <select id="lstemp" ng-model="Employee"
                        ng-options="emp as emp.EmpName for emp in Employees" ng-change="getEmployeeDetails()">

                </select>
            </td>
            <td>
                <div class="dv">
                    <table>
                        <tr>
                            <td>
                                <span>The Mobile No: {{Employee.ContactNo}}</span>
                            </td>
                        </tr>
                        <tr>
                            <td>
                                <span>The Phone No: {{Employee.PhoneNo}}</span>
                            </td>
                        </tr>
                        <tr>
                            <td>
                                <span>The Extension No: {{Employee.Extension}}</span>
                            </td>
                        </tr>
                    </table>
                    
                    
                </div>
            </td>
        </tr>
        <tr>
            <td>
                <input type="button" id="btnsave" value="Save" ng-click="save()" />
            </td>
        </tr>
    </table>
    <div>
        <span ng-model="status"></span>
    </div>
    <script src="~/lib/angularjs/js/angular.min.js"></script>
    <script src="~/lib/angularjs/js/app.js"></script>
    <script src="~/lib/angularjs/js/service.js"></script>
    <script src="~/lib/angularjs/js/controller.js"></script>
</body>
</html>

The above HTML refers to the Angular.js and other JavaScript files we have added in the project. The <input> elements are bound with the various $scope declarations defined in controller.js. The <select> elements are bound with Departments and Employees $scope to show Departments and Employees Information.

Run the Application and it will show Departments info as below:

aspnet5-app

Enter Visitor Details as shown below:

visitrdetails

Click on Save button, the Visitor Id will be displayed. Likewise the view and functionalities for Edit Visit, Get Visits, etc. can be added in the application.

Conclusion: Visual Studio 2015 with Unified ASP.NET 5 provides some handy features for developing business applications. In-built support for JavaScript libraries like Bower and Grunt help to manage project dependencies for the application, keeping a low maintenance for the web application.

Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+
Further Reading - Articles You May Like!
Author
Mahesh Sabnis is a DotNetCurry author and Microsoft MVP having over 17 years of experience in IT education and development. He is a Microsoft Certified Trainer (MCT) since 2005 and has conducted various Corporate Training programs for .NET Technologies (all versions). Follow him on twitter @maheshdotnet


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!
Comment posted by Jack on Tuesday, February 17, 2015 8:08 AM
What has happened to good old coding.  

These plethora of half baked technologies need a lot of training for the new people to get on the band wagon.  

Simple is better and usable.  

Why don't you guys go back to asp and improve that! lol.
Comment posted by MAhesh Sabnis on Tuesday, February 17, 2015 11:49 PM
Hi Jack,

  The model of the Programming of WEB on .NET is improved. Now we have ASP.NET 5 Stack where we have WEB Forms, MVC 6 ad WEB API. SO web Developers are having a choice to  select the technology and start code. This also provides inbuilt support for managing dependencies using which now it is easy to manage separate components of the applications e.g. DAL, BLL, etc. On the other side With the support of Client-Side JavaScript framework web developers can start building SPAs. The VS2015'f web features with an integration of GRUNT and BOWER makes client-Side JavaScript management better. So ASP.NET 5 is a umbrella where server-side and Client-Side both can be easily incorporated.
Thanks
Regards
Mahesh Sabnis
Comment posted by C. on Wednesday, February 18, 2015 7:30 AM
Hi Mahesh,

I think Jack may be touching on something. Classic ASP (more than 10 yrs.) appeared as a very simple server-side programming language. Its competitor Java/Java2 at that time was simplistic but powerful.

In modern app development, which he calls coding (an old term), MS has pushed developers (or themselves have been pulled) into a paradigm of ever-evolving technology stacks. MS can not have an irrelevant IDE so all possible stacks and technology must somehow be available to the developer.

The simple success of nodeJS could illustrate how a dominant, heavily invested platform such as ASP.NET can lose mindshare (or codeshare) if it is simple to learn and implement a working app in minutes versus hours. DNC tutorials on ASP.NET may not all be geared towards new developers.
Comment posted by Mahesh Sabnis on Friday, February 20, 2015 4:31 AM
Hi C,

You make some valid points and I do agree with what Jack said, it is just that a lot of right things are happening too soon. Yes the recent technology advancements can be overwhelming even for an intermediate level developer. However your comment has made Suprotim and I think that probably we need to step back a little and get the new developers up to speed before we try to keep at pace with MS.

Based on your feedback, we will work on a plan to create some tuts specifically for new developers and make them understand .NET's vision and why is it moving in that direction. If you could too provide some inputs on what areas do we need to cover, that'd be great!