Showing posts with label SQL Server. Show all posts
Showing posts with label SQL Server. Show all posts

4.15.2017

AngularJS CRUD, Entity FrameWork & Web API Step-By-Step Part Two

Introduction

This is Part Two of my Angular Step-By-Step tutorial.

Add BundleConfig.cs

  1. Select the App_Start folder. Right-Click and choose the Add from the context-menu.
  2. Add a new Class name it BundleConfig.cs.
  3. This class will use the following namespace using System.Web.Optimization;.
  4. Add the following static method public static void RegisterBundles(BundleCollection bundles)
  5. You may need to install the Microsoft.AspNet.Web.Optimization via NuGet - without it the BundleCollection will not instantiate.
  6. Now to configure this class to load the bundles. We will use the .IncludeDirectory method. Type the following code in the RegisterBundles method:
           bundles.Add(new StyleBundle("~/Content/VendorCss")
                .Include("~/Content/bootstrap.css")
                .Include("~/Content/bootstrap-theme.css")
                .Include("~/Content/font-awesome.css")
                .Include("~/Content/toastr.css"));

            bundles.Add(new ScriptBundle("~/Scripts/VendorJavaScript")
                .Include("~/Scripts/jquery-3.1.1.js")
                .Include("~/Scripts/bootstrap.min.js")
                .Include("~/Scripts/angular.js")
                .Include("~/Scripts/angular-route.js")
                .Include("~/Scripts/toastr.js")
                .Include("~/Scripts/lodash.js"));

Modify the Global.asax.cs File

  1. In the Solution Explorer scroll to the top, select Solution WorldPopulation.
  2. Select the Project WorldPopulation
  3. Expand the file named Global.asax.
  4. Open the file Global.asax.cs
  5. Add the following code to the Application_Start method
BundleConfig.RegisterBundles(BundleTable.Bundles);

NOTE You will need to add a reference to using System.Web.Optimization;.

the Global.asax.cs should now look something like the following:

    public class Global : HttpApplication
    {
        void Application_Start(object sender, EventArgs e)
        {
            // Code that runs on application startup
            AreaRegistration.RegisterAllAreas();
            GlobalConfiguration.Configure(WebApiConfig.Register);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }

Adding a RAZOR Index.cshtml page

Open the HomeController that was added in Step #7.

  1. The View() will be RED because there is no Index View (remember Model-View-Controller). Right-click on the word Index and select Add View from the popup.
  2. The next dialog will have several options, pick the above Layout Page you just added then click Add.
  3. Press Add.

Now this will insert a basic HTML page, and we need to modify it so the CSS and JavaScript bundles get loaded, and the Single Page Application will be setup.

Modify the Index.cshtml file to look like the following

 @{
    ViewBag.Title = "Index";
    Layout = "~/Views/_LayoutPage.cshtml";
}

<!DOCTYPE html>

@using System.Web.Optimization
<html ng-app="worldPopApp">
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>

    @Styles.Render("~/Content/VendorCss")

    @Scripts.Render("~/Scripts/VendorJavaScript")

    @Scripts.Render("~/bundles/Application")
</head>
<body>
    <div class="navbar navbar-inverse navbar-fixed-top">

        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a asp-area="" asp-controller="Home" asp-action="Index" class="navbar-brand">World Population</a>
        </div>
        <div class="navbar-collapse collapse">
            <ul class="nav navbar-nav">
                @*<li><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li>
                    <li><a asp-area="" asp-controller="Home" asp-action="About">About</a></li>
                    <li><a asp-area="" asp-controller="Home" asp-action="Contact">Contact</a></li>*@
            </ul>
        </div>

    </div>
    <hr /><hr />
    <div class="main container-fluid" ng-view>

    </div>
</body>
</html>

NOTE There is a bundle reference in this code to @Scripts.Render("~/bundles/Application"). This does not exist in the BundleConfig. We will set this up, and it will not cause the code to crash. It will throw an exception to the browser console.

Angular Directive ng-app

In the Index.cshtml there is a line of code that tells this web application it is an AngularJS application

<html ng-app="worldPopApp">

Use this directive to auto-bootstrap an AngularJS application. The ngApp directive designates the root element of the application and is typically placed near the root element of the page - e.g. on the or tags. There are a few things to keep in mind when using ngApp:

  • only one AngularJS application can be auto-bootstrapped per HTML document. The first ngApp found in the document will be used to define the root element to auto-bootstrap as an application. To run multiple applications in an HTML document you must manually bootstrap them using angular.bootstrap instead.
  • AngularJS applications cannot be nested within each other.
  • Do not use a directive that uses transclusion on the same element as ngApp. This includes directives such as ngIf, ngInclude and ngView. Doing this misplaces the app $rootElement and the app's injector, causing animations to stop working and making the injector inaccessible from outside the app.
You can specify an AngularJS module to be used as the root module for the application. This module will be loaded into the $injector when the application is bootstrapped. It should contain the application code needed or have dependencies on other modules that will contain the code. See angular.module for more information.

Angular Directive ng-view

In the Index.cshtml there is a line of code that injects web pages into Index.cshtml between the div.

Understanding SPA and ng-view can be found here: Single Page Apps with AngularJS Routing and Templating


    <div class="main container-fluid" ng-view>

    </div>

The basic startup view is setup, now we need to setup the AngularJS folder structure, app and routing.

AngularJS Folder Structure

As noted in AngularJS CRUD, Entity FrameWork & Web API Step-By-Step Part One the folder structure we will use is what John Papa recommended years ago, as defined here John Papa project structure.

Steps to Creating the Folder Structure

  1. Select the WorldPopulation Project.
  2. Right-Click the WorldPopulation Project, select New Folder from the context menu.
  3. Name the folder app (Case is critical)
  4. Select the newly created folder app, Right-click it and select New Folder from the context menu.
  5. Name the new folder controllers.
  6. Select the newly created folder app, Right-click it and select New Folder from the context menu.
  7. Name the new folder services.
  8. Select the newly created folder app, Right-click it and select New Folder from the context menu.
  9. Name the new folder views.

Now the basic folder structure for the AngularJS components is completed.

AngularJS Setup app.js

  1. Select the folder app. Right-click it and select Add from the context menu. Select JavaScript File.
  2. Type app in the popup dialog. Press OK

You are presented with an empty file. Paste in the code from below.


var app = angular.module('worldPopApp',
    [
        'ngRoute',
        'toastr'
    ]);

app.config([
    '$routeProvider', function ($routeProvider) {
        $routeProvider.when('/',
            {
                templateUrl: 'app/views/wpList.html',
                controller: 'wpListCtrl'
            }).otherwise({
                redirectTo: '/'
            });
    }
]);

NOTE I have identified an issue with Twitter Bootstrap v3.3.7 as of March 2017, that seems to cause an issue with the Angular UI-Grid - a really nice grid, not being used in this tutorial but one I use extensively over the Kendo-Grid. Just keep in mind, I had to down step my NuGet package for Bootstrap to use the UI-Grid in my personal projects, but I suspect this will be fixed soon.

Injecting the 'toastr' library may be an issue, I am debugging, so if you get any console errors simply comment it out using // and comment out the comma after the injection of the 'ngRoute'.

Now, lets add a VIEW, CONTROLLER and SERVICE. If you don't know what these are I strongly recommend you take any AngularJS 1.x tutorial. In the folder app/views insert the following code into a file named wpList.html (CASE IS IMPORTANT)


<style>
    .tablerow:hover, .tablecell:hover { background-color: #f4a460; }

    table { overflow: hidden; }

    .tablecell { position: relative; }

    .tablecell:hover::before {
        content: "";
        position: absolute;
        left: 0;
        top: -5000px;
        height: 10000px;
        width: 100%;
        z-index: -1;
        /* keep it below table content */
        background-color: #f4a460;
    }

    .tableheader { text-align: center; }
</style>
<div ng-controller="wpListCtrl as vm" ng-init="vm.init()">
    <div class="table-responsive">
        <table class="table table-striped table-bordered">
            <tr>
                <th style="width: 2%;" class="tableheader">Id</th>
                <th style="width: 90%;" class="tableheader">Country</th>
                <th style="width: 4%;"></th>
                <th style="width: 4%;"></th>
            </tr>
            <!--<pre>{{vm.worldpopulation.data | json}}</pre>-->
            <tr class="tablerow" ng-repeat="item in vm.worldpopulation.data">
                <td class="label-success">{{ item.COUNTRYID }}</td>
                <td>
                    <a class="btn btn-link" ng-click="vm.addCountry(item)" style="text-decoration: underline !important; padding: 0 !important; margin: 0 !important;"
                       href="">{{ item.COUNTRY_NAME }}</a>
                </td>
                <td>
                    <a href="#/edit/{{item.COUNTRYID}}" class="glyphicon glyphicon-edit"></a>
                </td>
                <td>
                    <a href="#/delete/{{item.COUNTRYID}}" class="glyphicon glyphicon-trash"></a>
                </td>
            </tr>
        </table>
    </div>
</div>

In the folder app/services insert the following code into a file named wpService.js (CASE IS IMPORTANT)


app.factory("wpService", ["$http", "$q",
    function ($http, $q) {
        var getWorldPopulationData = function () {
            var deferred = $q.defer();
            $http({
                method: 'GET',
                url: '/api/worldpopulation'
            }).then(function (dataResponse) {
                deferred.resolve(dataResponse);
                }, function (dataResponse) {
                    alert("error" + dataResponse);
                deferred.reject();
            });
            return deferred.promise;
        };

        var deleteWorldPopulation = function (data) {
            var deferred = $q.defer();
            $http.delete('/api/worldpopulation/' + data.COUNTRYId).then(function () {
                deferred.resolve(true);
            }, function () {
                alert("error");
                deferred.reject();
            });
            return deferred.promise;
        }

        var saveWorldPopulation = function (data) {
            var deferred = $q.defer();
            $http.post('/api/worldpopulation/', data).then(function () {
                deferred.resolve(true);
            }, function () {
                alert("error");
                deferred.reject();
            });
            return deferred.promise;
        }
        return {
            GetWorldPopulationData: getWorldPopulationData,
            DeleteWorldPopulation: deleteWorldPopulation,
            SaveWorldPopulation: saveWorldPopulation
        }
    }]);

In the folder app/controllers insert the following code into a file named wpListCtrl.js (CASE IS IMPORTANT)


(function () {
    'use strict';
    var controllerId = 'wpListCtrl';
    app.controller(controllerId, ['$scope', '$http', '$location', 'wpService', wpListCtrl]);

    function wpListCtrl($scope, $http, $location, wpNotesService) {
        var vm = this;
        vm.data = wpNotesService;
        vm.sort = 0;
        vm.currentSort = '';
        vm.moduleTitle = 'World Population Countries List';
        vm.worldpopulation = [];
        vm.isActive = false;
        vm.ViewModel = {
            StatusCode: 'A'
        }


        vm.init = function () {
            vm.loadData();

        };

        vm.loadData = function () {
            vm.data.GetWorldPopulationData().then(function (data) {
                vm.worldpopulation = data;
            });
        }

        vm.GetStatus = function (data) {
            if (data.StatusCode === 'A')
                vm.isActive = true;
            vm.isActive = false;
        };
    }
}
)();

Modify the Global.asax.cs File

We need to modify the Global.asax.cs again because our data is coming from the database in EntityFramework and the properties are not serializing the data into a format that can be used easily in the client. so below the Application_Start add the following:

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
           GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);

Before this modification, when running the application you may see an error such as: The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'." There are several means to address this like

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize;
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);

But this solution is wrong. This is JSON and XML Serialization in ASP.NET Web API

4.12.2017

AngularJS CRUD, Entity FrameWork & Web API Step-By-Step Part One

Introduction

I am a full-stack web programmer for the State Department. We work with AngularJS 1.2 mixed with WEB API, WCF and SQL Server - our own hybrid architecture.

It is how I learned this tech. But I wanted to create other Angular based projects, some to help my friends with their hobbies (feral Cats), others to simply solidify my AngularJS understanding - just before I take the leap into AngularJS 2.0…

So I created lots of CRUD apps, and I like the John Papa project structure - so this post is about building an AngularJS CRUD project using the MVC and WEBAPI template, and Entity Framework

Project Requirements

The project will be based on this table at the website wikipedia. This is a table that lists countries by population and captures the change by year in population.

Scope of Step #1

This step simply gets the database up and running.

Data Model

In this project example, I am going to use the Entity Framework Database First - using Microsoft SQL Server.

Scripts

The database scripts are as follows:

CREATE TABLE COUNTRY(
    COUNTRYID int IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED,
    COUNTRY varchar(100) NULL,
    CONTINENTIAL_REGIONID int NULL,
    STATISTICAL_REGIONID int NULL
) 
GO

CREATE TABLE UN_CONTINENTAL_REGION(
    CONTINENTIAL_REGIONID int IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED ,
    CONTINENTIAL_REGION varchar(250) NULL
) 

GO

CREATE TABLE UN_STATISTICAL_REGION(
    STATISTICAL_REGIONID int IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED,
    STATISTICAL_REGION varchar(250) NULL
    )

CREATE TABLE dbo.[POPULATION](
    POPULATIONID int IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED ,
    COUNTRYID int NULL,
    YEARID int NULL,
    POPULATION int NULL
    )
GO

CREATE TABLE YEAR_DOMAIN(
    YEARID int NOT NULL PRIMARY KEY CLUSTERED
    )
GO

ALTER TABLE COUNTRY  WITH CHECK ADD  CONSTRAINT FK_COUNTRY_UN_CONTINENTAL_REGION 
FOREIGN KEY(CONTINENTIAL_REGIONID) REFERENCES 

UN_CONTINENTAL_REGION (CONTINENTIAL_REGIONID)
GO

ALTER TABLE COUNTRY CHECK CONSTRAINT FK_COUNTRY_UN_CONTINENTAL_REGION
GO

ALTER TABLE COUNTRY  WITH CHECK ADD  CONSTRAINT FK_COUNTRY_UN_STATISTICAL_REGION 
FOREIGN KEY(STATISTICAL_REGIONID) REFERENCES 
UN_STATISTICAL_REGION (STATISTICAL_REGIONID)
GO

ALTER TABLE COUNTRY CHECK CONSTRAINT FK_COUNTRY_UN_STATISTICAL_REGION
GO

ALTER TABLE POPULATION  WITH CHECK ADD  CONSTRAINT FK_POPULATION_COUNTRY 
FOREIGN KEY(COUNTRYID) 
REFERENCES COUNTRY (COUNTRYID)
GO

ALTER TABLE POPULATION CHECK CONSTRAINT FK_POPULATION_COUNTRY
GO

ALTER TABLE POPULATION  WITH CHECK ADD  CONSTRAINT FK_POPULATION_YEAR_DOMAIN 
FOREIGN KEY(YEARID) REFERENCES YEAR_DOMAIN (YEARID)
GO

ALTER TABLE POPULATION CHECK CONSTRAINT FK_POPULATION_YEAR_DOMAIN
GO

These scripts will create five tables. COUNTRY, UN_CONTINENTAL_REGION,POPULATION,YEAR_DOMAIN and UN_STATISTICAL_REGION.

Probably overkill, but this is for illustration of multiple technologies in a very simple application.

Need some data scripts to populate the database:

INSERT INTO YEAR_DOMAIN
(YEARID) VALUES(2015);

INSERT INTO YEAR_DOMAIN
(YEARID) VALUES(2016);

INSERT INTO YEAR_DOMAIN
(YEARID) VALUES(2017);

INSERT INTO UN_CONTINENTAL_REGION
(CONTINENTIAL_REGION) VALUES('ASIA');

INSERT INTO UN_CONTINENTAL_REGION
(CONTINENTIAL_REGION) VALUES('AMERICAS');

INSERT INTO UN_CONTINENTAL_REGION
(CONTINENTIAL_REGION) VALUES('AFRICA');

INSERT INTO UN_CONTINENTAL_REGION
(CONTINENTIAL_REGION) VALUES('EUROPE');

INSERT INTO UN_CONTINENTAL_REGION
(CONTINENTIAL_REGION) VALUES('OCEANIA');

INSERT INTO UN_STATISTICAL_REGION
(STATISTICAL_REGION) VALUES('Eastern Asia')

INSERT INTO UN_STATISTICAL_REGION
(STATISTICAL_REGION) VALUES('Southern Asia')

INSERT INTO UN_STATISTICAL_REGION
(STATISTICAL_REGION) VALUES('Northern America')

INSERT INTO UN_STATISTICAL_REGION
(STATISTICAL_REGION) VALUES('South-Eastern Asia')

INSERT INTO UN_STATISTICAL_REGION
(STATISTICAL_REGION) VALUES('South America')

INSERT INTO UN_STATISTICAL_REGION
(STATISTICAL_REGION) VALUES('Australia and New Zealand')

DECLARE @CNREGID INT, @STATREGID INT
SELECT @CNREGID=CONTINENTIAL_REGIONID FROM 
    UN_CONTINENTAL_REGION WHERE CONTINENTIAL_REGION='ASIA'
SELECT @STATREGID=STATISTICAL_REGIONID FROM 
    UN_STATISTICAL_REGION WHERE STATISTICAL_REGION='Eastern Asia'

INSERT INTO COUNTRY
(COUNTRY, CONTINENTIAL_REGIONID,STATISTICAL_REGIONID)
VALUES('CHINA',@CNREGID,@STATREGID)

SELECT @STATREGID=STATISTICAL_REGIONID FROM 
    UN_STATISTICAL_REGION WHERE STATISTICAL_REGION='Southern Asia'

INSERT INTO COUNTRY
(COUNTRY, CONTINENTIAL_REGIONID,STATISTICAL_REGIONID)
VALUES('INDIA',@CNREGID,@STATREGID)

SELECT @STATREGID=STATISTICAL_REGIONID FROM 
    UN_STATISTICAL_REGION WHERE STATISTICAL_REGION='South-Eastern Asia'

INSERT INTO COUNTRY
(COUNTRY, CONTINENTIAL_REGIONID,STATISTICAL_REGIONID)
VALUES('INDONESIA',@CNREGID,@STATREGID)

SELECT @CNREGID=CONTINENTIAL_REGIONID FROM 
    UN_CONTINENTAL_REGION WHERE CONTINENTIAL_REGION='AMERICAS'
SELECT @STATREGID=STATISTICAL_REGIONID FROM 
    UN_STATISTICAL_REGION WHERE STATISTICAL_REGION='Northern America'

INSERT INTO COUNTRY
(COUNTRY, CONTINENTIAL_REGIONID,STATISTICAL_REGIONID)
VALUES('UNITED STATES',@CNREGID,@STATREGID)

SELECT @STATREGID=STATISTICAL_REGIONID FROM 
    UN_STATISTICAL_REGION WHERE STATISTICAL_REGION='South America'

INSERT INTO COUNTRY
(COUNTRY, CONTINENTIAL_REGIONID,STATISTICAL_REGIONID)
VALUES('BRAZIL',@CNREGID,@STATREGID)


SELECT @CNREGID=CONTINENTIAL_REGIONID FROM 
    UN_CONTINENTAL_REGION WHERE CONTINENTIAL_REGION='OCEANIA'
SELECT @STATREGID=STATISTICAL_REGIONID FROM 
    UN_STATISTICAL_REGION WHERE STATISTICAL_REGION='Australia and New Zealand'

INSERT INTO COUNTRY
(COUNTRY, CONTINENTIAL_REGIONID,STATISTICAL_REGIONID)
VALUES('AUSTRALIA',@CNREGID,@STATREGID)

DECLARE @COUNTRYID INT;
SELECT @COUNTRYID=COUNTRYID FROM COUNTRY WHERE COUNTRY='CHINA'
INSERT INTO dbo.[POPULATION] (COUNTRYID,YEARID,POPULATION)
VALUES(@COUNTRYID,2015,1376048943)

INSERT INTO dbo.[POPULATION] (COUNTRYID,YEARID,POPULATION)
VALUES(@COUNTRYID,2016,1382323332)

SELECT @COUNTRYID=COUNTRYID FROM COUNTRY WHERE COUNTRY='INDIA'
INSERT INTO dbo.[POPULATION] (COUNTRYID,YEARID,POPULATION)
VALUES(@COUNTRYID,2015,1311050527)

INSERT INTO dbo.[POPULATION] (COUNTRYID,YEARID,POPULATION)
VALUES(@COUNTRYID,2016,1326801576)

SELECT @COUNTRYID=COUNTRYID FROM COUNTRY WHERE COUNTRY='UNITED STATES'
INSERT INTO dbo.[POPULATION] (COUNTRYID,YEARID,POPULATION)
VALUES(@COUNTRYID,2015,321773631)

INSERT INTO dbo.[POPULATION] (COUNTRYID,YEARID,POPULATION)
VALUES(@COUNTRYID,2016,324118787)


SELECT @COUNTRYID=COUNTRYID FROM COUNTRY WHERE COUNTRY='INDONESIA'
INSERT INTO dbo.[POPULATION] (COUNTRYID,YEARID,POPULATION)
VALUES(@COUNTRYID,2015,257563815)

INSERT INTO dbo.[POPULATION] (COUNTRYID,YEARID,POPULATION)
VALUES(@COUNTRYID,2016,260581100)

SELECT @COUNTRYID=COUNTRYID FROM COUNTRY WHERE COUNTRY='BRAZIL'
INSERT INTO dbo.[POPULATION] (COUNTRYID,YEARID,POPULATION)
VALUES(@COUNTRYID,2015,207847528)

INSERT INTO dbo.[POPULATION] (COUNTRYID,YEARID,POPULATION)
VALUES(@COUNTRYID,2016,209567920)

SELECT @COUNTRYID=COUNTRYID FROM COUNTRY WHERE COUNTRY='AUSTRALIA'
INSERT INTO dbo.[POPULATION] (COUNTRYID,YEARID,POPULATION)
VALUES(@COUNTRYID,2015,23968973)

INSERT INTO dbo.[POPULATION] (COUNTRYID,YEARID,POPULATION)
VALUES(@COUNTRYID,2016,24309330)

Scope of Step #2

This step is to get the Visual Studio Solution created.

Visual Studio

One of my colleagues loves to do his web development in JetBrains WebStorm - he swears by it, but I am a life long Visual Studio junkie. As of this writing, I am coding this post using Visual Studio 2017 Community Edition - a first for me, I usually use Professional or Enterprise, but heck, the Community version is so well loaded I love it.

Creating The Project

Open Visual Studio.

  1. Create New Project.
  2. When the dialog appears, select Web from the Installed Templates treeview. The middle list will populate, with varying options. Please select ASP.NET Web Application (.NET Framework)
  3. Select a Name, I am picking WorldPopulation along with a location to place the solution.

  4. When the next dialog pops up, among the templates - select Empty BUT look at the checkboxes below. We need to add in some CORE References. Make sure to check MVC and Web API.

  5. Do not select Add Unit Tests - we will do that but will not use the VisualStudio.TestTools.UnitTesting - rather we will use NUnit.

So, what are those other templates? Lots of tutorials simply skip explaining that. I will take a shot at explaining so you can have an understanding of what you are NOT doing at this point in time.

Note: Also see ASP.NET Web Application Projects and Web Application Projects versus Web Site Projects in Visual Studio.

The Empty template is simply what the name says, a empty web project, bare bones. This template creates an ASP.NET web application that includes a Web.config file, but no other files. Use this project template when you do not require the functionality built into the standard template.

The Web Forms template is server based web applications. All the code resides in the IIS server and gets rendered to the client. It is older technology and not used much for modern development.

According to Microsoft, it is:
Use this project template to create a web application that is based on ASP.NET Web Forms pages and that includes the following functionality. You can choose not to use any of these features when they are not required for your application.
  • A master page.
  • A cascading style sheet.
  • Login security that uses the ASP.NET membership system.
  • Ajax scripting that uses jQuery.
  • Navigation that uses a menu control.
By default, the ASP.NET Web Application project template includes the following:
  • Folders to contain membership pages, client script files, and cascading style sheet files.
  • A data folder (App_Data), which is granted permissions that allow ASP.NET to read and write to it at run time.
  • A master page (the Site.master file).
  • Web pages named Default.aspx, Contact.aspx, and About.aspx. These content pages are based on the default master.
  • A global application class (Global.asax file).
  • A Web.config file.
  • A Packages.config file.
  • For more information, see ASP.NET Web Application Projects and Web Application Projects versus Web Site Projects in Visual Studio.

The MVC template, that is Microsoft’ Model-View-Controller template. There are many incarnations of this approach, MVVM, etc., but basically the View (what you see in the web browser) is separate from the Controller (logic) and the Model (data). That is a simplistic explanation.

Use this project template to create web applications that use a model-view-controller pattern, using the ASP.NET MVC 3 release. The MVC pattern helps separate the different aspects of the application (input logic, business logic, and UI logic), while providing a loose coupling between these elements. In addition, this project template promotes test-driven development (TDD).

The Web API is what my friend Van told me once is “Microsoft’ replacement for WCF”. It is much easier to implement, lightweight, flexible. More on this later.

The Single Page Application is a design where there is a single web page that the user sees but portions of the page can load as needed.

When selecting those templates the Solution takes on a predefined structure and loads a lot of predefined files to get the developer up and running quickly. If CORE References is selected for MVC then components needed to do MVC applications are added but the structure of the solution is not populated with a lot of predefined components which a developer doesn’t necessarily need.

WorldPopulation Project

Now that the WorldPopulation (or whatever you called your own implementation of the solution) has been created, it should have one project with the same name.

That project should have 5 Folders:

  1. App_Data
  2. App_Start
  3. Controllers
  4. Models
  5. Views

The App_Start folder will have two files in it

  1. RouteConfig.cs
  2. WebApiConfig.cs

These are critical to how our application will work. More on that later.

Now we need to add two more projects to the solution.

  1. WorldPopulation.EF (for Entity Framework, or maybe Datalayer)
  2. WorldPopulation.UnitTests

Adding Projects


Add Unit Test Project

  1. In the Solution Explorer scroll to the top, select Solution WorldPopulation.
  2. Right-click the WorldPopulation solution.
  3. When the context-menu pops up, select Add.
  4. When the second context-menu expands, select New Project.
  5. In the template selector, change to Visual C#.
  6. In the middle listing of templates - select Class Library (.NET Framework)
  7. In the Name enter WorldPopulation.EF
  8. Press OK

Add Unit Test Project

  1. In the Solution Explorer scroll to the top, select Solution WorldPopulation.
  2. Right-click the WorldPopulation solution.
  3. When the context-menu pops up, select Add.
  4. When the second context-menu expands, select New Project.
  5. In the template selector, change to Visual C#.
  6. In the middle listing of templates - select Class Library (.NET Framework)
  7. In the Name enter WorldPopulation.UnitTests
  8. Press OK

NuGet Packages

For this example, I am going to use NuGet. I know that Bower and NPM has more recent updates, but for some of the non-web portions NuGet is awesome (plus I like it).

  1. In the Solution Explorer scroll to the top, select Solution WorldPopulation.
  2. Right-click the WorldPopulation solution.
  3. When the context-menu pops up, select Manage NuGet Packages for Solution.
  4. Click Browse at the top.
NuGet Package WorldPop WorldPop.EF WorldPop.UnitTests
Entity Framework X X X
NLog X X X
NLog.Config X X X
NUnit X
NUnit3TestAdapter X
AngularJS.Core X
AngularJS.Route X
bootstrap X
FontAwesome X
lodash X
jQuery X
toastr X

jQuery may already installed by other packages like Bootstrap or by the MVC references. Select jQuery in the NuGet package manager and choose the highest available version, then select update if the installed version is below thehighest available one.

When the NuGet package installation step is completed, you will see several additional folders in the WorldPopulation Project:

  1. Content
  2. Fonts
  3. Scripts

Content Folder

This folder mainly contains CSS related files, style sheets.

Fonts

The name is self-descriptive. The customized fonts provided by the Font Awesome libraries are stored within this folder.

Scripts

JavaScript files, AngularJS, Moment.JS, jQuery, etc., all are stored in this folder.

The other NuGet packages such as NLog or Entity Framework are added to the project references.

Scope of Step #3

In this step, we will create the Data Context by connecting to the database and retrieving the model into Visual Studio.

Project WorldPopulation.EF

  1. Select the WorldPopulation.EF Project.
  2. Right click the project and click Add on the popup context menu.
  3. Select New Folder, and enter Interfaces.
  4. Repeat steps 1-3, only enter Models instead of Interfaces for the new folder name this time.
  5. Select the Models folder you just created.
  6. Right-click and select Add from the first context menu, then New Item from the second.
  7. Select Data from the templates category on the left, then when it is filtered select ADO.NET Entity Data Model.
  8. For the name enter WPModel. Then click *Add.
  9. When the next dialog opens, select EF Designer from database.
  10. Click Next.
  11. In the Choose Your Data Connection dialog, enter the SQL Server connection information where you created the tables in Step #1.
  12. Let the settings be the default for the App.Config in my case, my SQL Server database was named DEV so the name of the connection string in App.Config is DEVEntities.
  13. In the next dialog, Choose Your Database Objects and Settings -we are only selecting the tables. Expand the tables, schema. Select:
TABLE NAME
COUNTRY
POPULATION
UN_CONTINENTAL_REGION
UN_STATISTICAL_REGION
YEAR_DOMAIN


Additional Options Yes/No
Pluralize or Singularize Generated Object Names Yes
Include Foreign Key Columns in the Model Yes
Import selected Stored Procedures and functions into the entity model No

MODEL NAMESPACE DEVModel

Remember DEV is my database name, so whatever you choose will be here

  1. Click Finish

Visual Studio will chug along as it reads the database, getting the model and generates the classes.

When it is done, you will see a visual representation of the SQL Server tables and their relationships in an EDMX file within the Models folder (remember how I had you select it before you started adding the ADO.NET Entity Data Model).

Under the file WPModel.tt you will see the class files for each table in the database.

Under the file WPModel.Context.tt is the WPModel.Context.cs this is the datacontext. I am not going to spend a lot of time explaining this, but you need to read more on this from the MSDN or EntityFramework Tutorial


Scope of Step #4

We need to create our Repository, a tiny one.
We will be working in the WorldPopulation.EF Project. We will be implementing the Implementing the Repository and Unit of Work Patterns in an ASP.NET MVC Application (9 of 10) which basically is

“The repository pattern is an abstraction. It’s purpose is to reduce complexity and make the rest of the code persistent ignorant. As a bonus it allows you to write unit tests instead of integration tests.”

Repository Pattern Resources

Steps to Pattern Implementation

  1. Select WorldPopulation.EF Project.
  2. Select the Interfaces Folder.
  3. Right click the context menu, click Add select Class.
  4. Enter IRepository.cs. Click OK.
  5. Open the file IRepository.cs. Modify class IRepository to public interface IRepository.
  6. The interface should be similar to the following:

    
    using WorldPopulation.EF.Models; 
    using System.Collections.Generic;
    namespace WorldPopulation.EF.Interfaces
    {
    public interface IRepository
    {
    List GetCountries();
    COUNTRY GetCountry(int countryID);
    }
    }

  1. Select the Models Folder.
  2. Right click the context menu, click Add select Class.
  3. Enter Repository.cs. Click OK.
  4. We are creating the Repository Pattern and implementing the Interface above in the folder Models in the file named Repository.cs.
  5. Be sure to add the following namespace reference at the beginning of the file:
  6. WorldPopulation.EF.Interfaces;
  7. Type the following code into the file Repository.cs :

using WorldPopulation.EF.Interfaces;
using System.Collections.Generic;
namespace WorldPopulation.EF.Models
{
     public class Repository : IRepository
     {
          private DEVEntities dbConn;
          public Repository()
          {
               dbConn=new DEVEntities();
          }

          public List<COUNTRY> GetCountries()
          {
               throw new NotImplementedException();
          }

          public COUNTRY GetCountry(int countryID)
          {
               throw new NotImplementedException();
          } 
     } 
}

Scope of Step #5

Now we get into the grit.

I still consider myself new to [TDD]TDD (Test-Driven Development).

Update Unit Test

  1. Add reference to WorldPopulation.EF project.
  2. Select WorldPopulation.UnitTests. Rename the file Class1.cs to DatalayerUnitTests.cs.
  3. Open the file DatalayerUnitTests.cs
  4. Add using NUnit.Framework; to class.
  5. Above the class name public class DatalayerUnitTests add the attribute [TestFixture].
  6. Create private member private IRepository repo; You will need to add a reference to the namespace using WorldPopulation.EF.Interfaces;.
  7. Create a new void method named Setup() with the attribute [Setup].
  8. Add a method named public void Setup() just below the [Setup] attribute. In this method add the following line:
    repo=new Repository(); You will need to import using WorldPopulation.EF.Models; namespace.
  9. Now create our first failing unit test.
        [Test]
        public void GetCountries_ExpectNone()
        {
            repo.GetCountries();
            Assert.That(repo!=null);
        }

NOTE This unit test as written will fail. When you open the repo.GetCountries() implementation, the code is

        public List<COUNTRY> GetCountries()
        {
            throw new NotImplementedException();
        }

Technically, we should be using a MOCK Interface for this but I am short on time so I am going to violate TDD and have the Unit Test become a Integration Test by accessing the data.

Modify the implementation as follows:

        public List<COUNTRY> GetCountries()
        {
            return dbConn.COUNTRies.ToList();
        }

Scope of Step #6

Switch to the WorldPopulation Project.

  1. Select Controllers folder.
  2. Select Add from the context-menu.
  3. Select Controller… from the second context-menu.
  4. Select Web API 2 Controller - Empty* then press Add.
  5. When the next dialog appears type WorldPopulation and the new controller name should be WorldPopulationController.
  6. Press the Add button.
  7. You should see a new file added into the folder Controllers with the name WorldPopulationController.cs.
  8. When the file opens, expand the curly braces.
  9. Create a Controller Constructor to instantiate the IRepository interface. You may need to add a reference to the WorldPopulation.EF project
        private IRepository repo;

        public WorldPopulationController()
        {
            repo=new Repository();
        }
  1. Now to create a method that will be used by the presentation layer (WEB SITE).
  2. Below the constructor, type the following attribute (type a few spaces first) [HttpGet]
  3. Below that attribute type [ActionName("GetCountries")]
  4. Now type below that attribute, type in:
        public IEnumerable<COUNTRY> GetCountries()
        {
           return repo.GetCountries();
        }

The entire function should look like:

        [HttpGet]
        [ActionName("GetCountries")]
        public IEnumerable<COUNTRY> GetCountries()
        {
           return repo.GetCountries();
        }

Scope of Step #7

Step #7 will begin to add some basic navigation components to the main web project. A HomeController a basic layout page and the default index.cshtml page.

Starting with the HomeController

Controller classes in AMVC are used to prepare the Model that will be mapped to a view for a particular resource. In this example, AMVC created the following Home Controller that will be used to return the default view for our application.

  1. Select Controllers folder.
  2. Select Add from the context-menu.
  3. Select Controller… from the second context-menu.
  4. Select MVC 5 Controller - Empty then press Add*.
  5. When the next dialog appears type Home and the new controller name should be HomeController.
  6. Press the Add button.
  7. You should see a new file added into the folder Controllers with the name HomeController.cs.
  8. Open the *HomeController.

You should see the following:

        // GET: Home
        public ActionResult Index()
        {
            return View();
        }
Now we are going to add some view to the project.
  1. Select the Views folder. Right-Click and choose the Add from the context-menu.
  2. Select MVC 5 Layout Page (Razor). In the popup, select _LayoutPage as the file name.
  3. Paste the following code into the new _LayoutPage.cshtml file:
 <!DOCTYPE html>
 <html>
 <head>
     <meta charset="utf-8" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title - My ASP.NET Application</title>
    <link href="~/Content/Site.css" rel="stylesheet" type="text/css" />
    <link href="~/Content/bootstrap.min.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <div class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                @Html.ActionLink("World Population", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav"></ul>
            </div>
        </div>
    </div>

    <div class="container body-content">
        @RenderBody()
        <hr />
        <footer>
            <p>&copy; @DateTime.Now.Year - WorldPopulation</p>
        </footer>
    </div>

    <script src="~/Scripts/jquery-3.1.1.min.js"></script>
    <script src="~/Scripts/bootstrap.min.js"></script>
</body>
</html>

7.14.2008

First OpenSource Project Up! Work Starts.


Hello, this is the 3rd time I write this post.

Now, why your asking is this the 3rd time?
Because I don't have much luck with blog editors! Especially
Google's, that is why I am now using their new improved one. I just hope it doesn't mess up my formatting again. All I want to do is write, compose and post! But this is a serious struggle.

This time I am using ScribeFire. An Add-on that is integrated into my FireFox browser. It is VERY cool. I MEAN AWESOME! I can even size it to my 22' screen! Google doesn't miss the boat on too many thins, but here, well it sailed.
Now on to the post.  -

P.S.  - Post, action Post Update

While ScribeFire was excellent for me managing, creating, and posting - my little evil friend at Google somehow managed to mangle the nice presentation... I simply grabbed the text, placed <font> tags at beginning, and end, with a few <a hrefs...>, inserted the tag for the <image> and called it quits....UNCLE I said..



Background

Its about my first Open Source project I just posted a CodePlex.

"CodePlex is Microsoft's open source project hosting web site."

A definition of the service from the CodePlex team. Since I am focused on the .NET programmer (do other non- - it made sense for me to try my first open source project here instead of SourceForge.NET.

So I had to pick a project. Well I was working on developing all kinds of IDE Add In's for work and home. Integrated source reflectors, automated solution backup - based on ZipStudio [Upgraded ZipStudio source is at "Willem Rue" Blogz, a NICE Add-In that really helped me a lot once I automated the backup process at the project level], and some others. The same things I see out here now.

I had already developed a version of SQLString as task tray application, and was using it - but this was an opportunity to re-develop the idea and take it much further, and at the same time learn a brand new (for me) namespace (was NOT going back to do the Compact one!!).

 

What is SQLString?

So, this project - SQLString what is it?

SQLString is a simple SQL code generator that works within the Visual Studio 2005/2008 IDE. I had used a SQL code generator many years ago years ago and loved it.  I knew it could help me now,  but could never find it except in websites. Where I work - access to the web isn't reliable, or fast so I made my own. (NOTE to boss, this version, I made at home - off the clock).

The initial requirements were simple enough, but they grew. I couldn't make a version 2 without some serious enhancements!

Functional Requirements (blah blah blah - ode to a friend)
  1. Allow the user to either paste or have linked into the control a specific SQL statement.
  2. Select a target language and based on the language chosen, allow the user to select from a pre-defined list of data types compatible with the selected language (I am NOT a functional, but many friends are!!!)
  3. Enable the user to select a customizable template, or additional "header" and "footer" snippets (Visual Studio 2005 Code Snippets for example...).  [Best example I could come up with]
  4. Generate a source code statement which is compatible with the selected language.

    Base User Parameters related to SQL Code Generation

    1. Default the generated statement into a standard variable or allow the user to define a variable. 
    2. Define the "wrap" point for the characters in the generated statement. Default is 80, which currently means if a WORD will cause the generated string to exceed that parameter it will be wrapped to the next line. 
    3. Enable the generated SQL statement to be:

  • 1. Allow the user to insert the generated statement into the current IDE document at :

  • this.ApplicationObject.ActiveDocument.Object("TextDocument") as TextDocument;

  • 2. Enable the user to save the results into both the CODEKeep Library and XML Files.   CODEKeep (my current customers would recognize) is a place to store the generated SQL/Program Logic.  Like a storage for it - permanently, but with the ability to generate daily changes to the db and export them as XML or - whatever.



I know, wild!! I even went to Microsoft Research to check on the other language they have released for the IDE named F#. If it will be in the IDE, I was going to support it.

Ready For CODEPLEX

I know which project I will submit to CodePlex, just need to make sure I have it documented enough for them. The few options that CodePlex presents in the beginning for a new project are:

  1. Name
  2. Description (up to 2000 chars, but only the first 190 can be seen - DUH!!)
  3. URL.
  4. Email verification.


HA!!

Glad I was prepared.

Of course I may have gone overboard for a simple SQL Code Generator, but I like to have more documentation than too little. After your project is created, now you must provide details.

Project Description

Here you provide more detail on what the project is, and does. But now the fun begins because who wants to provide such information to the world in plain text, when there is a nice markup language available? So, now you have to learn that! Not a problem, but I couldn't figure out how to set an external URL to have a nice name IBM like instead of showing www.ibm.com.

I lost a lot of time playing with that trying various permutations on their URL command like:

[url:www.ibm.com]IBM and [url:www.ibm.com , title=IBM],and several others. None of which worked (CodePlex is new, so I am patient).

Doing a list or table was so easy, I almost abused it. I then provided some screenshots so users would have context. Meanwhile there is this enormous message in big red letters reminding me that I had

30 DAYS TO PUBLISH OR MY PROJECT WILL BE DELETED.

That is motivating!! I can understand though. Disk is expensive!! (Well until I walked into Best Buy last week and saw 1TB external USB drives on sale for 199!!! - I am running out of ports).


Add Team Members

This was a one man show. If someone wants to help, no problem! But no one to define.


Upload Source

Now, this is where the fun begins. CodePlex offers many source code control tools to integrate with, from Team Explorer Client (Microsoft Solution) to TortoiseSVN. I had already narrowed my choices to TortoiseSVN or to the CodePlex Client - a command line based utility which had directly interface to the TFS servers at CodePlex.

Since I had not used any Subversion based tools, I felt more comfortable with the CodePlex Client. I still have to get TortoiseSVN for work!!

Now there is a nice configuration file to which must be created, with some documentation (minimal at best). The moment I added in the parameters for my Diff and Merge tools, it thew exceptions. With no handler, to get any reason why.

Note to self:
Next time you have this situation and the source code and an ERROR - fix it.  I mean, I had the code, I knew the language, I could do what was needed to fix it..but I was thinking in the box....DUH!!


So I start taking out the parameters one by one. Eventually - it comes back to a working state when there are virtually NO PARAMETERS!

(What I learn through much trial and error is that I should wait to establish comm from my system to CodePlex servers with the Client - BEFORE setting the SourceGear or TortoiseMerge/Diff tool parameters...)

Fine, so, now I need to:check-in my project for the first time!


But there is no such command in the CodePlex Client. OK, fine, I try add - but that is to add files/directories after they are checked out- DUH!?

Now, remember - I have NO project files on their server. I search thru the Wiki and find some answer...

cpc checkout [projectname]

Which is so logical!

This I learn from someone who stayed up very late trying to use the CodePlex Client - and he was kind enough to post his notations into the Wiki.

Eventually - I get the project uploaded.


Select A License

I thought I might select the GNU license, but I went around and looked at a lot of the licenses other projects had, and was surprised in the variety. When researching the Open Source Foundation, they had so many licenses, even NASA had an open source license - I just went and decided to use the Microsoft one. No particular reason why, just hope they don't get any rights because of it!


Update the Issues

There were several. I think the most critical being the data model is still in flux.


Create A Release

Now this was interesting. I had already created the base set of files when I uploaded changeset 19719. But for a Release, it did not draw from what was checked into the repository but required I upload files from my local file system - again.

Along with each file - provide a description. I created the Alpha Release 001 and placed it into PLANNED status.

CodePlex gives you several statuses for a Release

(Which we may review for adoption on my current project)

  1. Alpha—the first feature-complete build of the software that is ready for testing. Some developers may also use the term "Alpha” for software with limited functionality.
  2. Beta—a feature-complete build of the software that has passed system and regression testing.
  3. Nightly Build—as implied, a build of the software generated after the developers have completed their work for the day. This is often an automated build.
  4. Production—the final release to be delivered to the end users.
  5. Release Candidate—a build of the software that is potentially ready for final release to the end user, barring any “show-stopping” issues that come to light.
  6. Special Build—a software build that is generated for any particular reason, often at the request of a project member or members.
Tags

Now update the "tags" that I think should be used as part of a search in order for people to find my project. I select several, from .NET 2.0 to Java/J#.


Status Check

OK, I have made the new project - provided detailed information on it's design, uploaded the files, selected a license, identified issues, created a release - OH yes - PUBLISH IT!!!

There is still more to do,

Add News Feeds and but the most difficult part for me...

After You Publish Your Project, Increase Traffic and Evangelize Your Project

I was never a salesman!! But we shall see how it goes.


Now work Begins!!


Oh, and this is a screenshot of SQLString in action!!