Cascading Dropdown List in ASP.Net MVC a sample demonstration

Last couple of weeks I found a good number of requests from my trainees and some .NET developers. They request me for sample code or a demonstration of cascading dropdown list in ASP.NET MVC. That’s why, I am writing this article. Cascading dropdown list is actually a parent child dropdown list. In this article I showed two dropdown lists one is category dropdown list and other is product dropdown list. Product dropdown list will be populated on the basis of category (selected category).

Let’s implement cascading dropdown list in ASP.NET MVC

Tools and Technology used
I used following tools and technology to develop the project –

1. Visual Studio 2013
2. Visual C#
3. ASP.NET MVC 5
4. Entity Framework 6
5. JQuery Ajax

Step 1: Create a ASP.NET MVC Project
Open visual studio and then go
File -> Project -> ASP.NET Web Application
Create an ASP.NET MVC project

Step 2: Install Json.NET
Click right button on Project -> NuGet Packages

2015-12-04-01

  • Select and install Json.NET

2015-12-04-02

Keep note that in this moment, your internet connection must on.

Step 3: Create a local database
Click right button on App_Data folder -> Select Add -> SQL Server Database.

2015-12-04-03

Type Item name as InventoryDB. You can choose any type you want. You will see Inventory.mdf file is created in App_Data folder

Step 4: Modify connection string.
Modify connection string as below because you are using localdb.


  
    
  

Step 5: Create a model for the application.

Create a model name Category in model folder

    public class Category
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public List Products { get; set; }
    }

Create a model name Product in model folder

    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public int CategoryId { get; set; }

        [ForeignKey("CategoryId")]
        public virtual Category Category { get; set; }
    }

Create a model name Item in model folder

    public class Item
    {
        public int Id { get; set; }
        public string Name { get; set; }

        [Display(Name = "Category")]
        public int CategoryId { get; set; }
        [ForeignKey("CategoryId")]
        public virtual Category Category { get; set; }

        [Display(Name = "Products")]
        public int ProductId { get; set; }
        [ForeignKey("ProductId")]
        public Product Product { get; set; }
    }

Step 6: Create Context Class
Create a context class in model folder name InventoryDBContext as follows

    public class InventoryDBContext : DbContext
    {
        public InventoryDBContext()
            : base("DefaultConnection")
        {

        }

        public DbSet Categories { get; set; }
        public DbSet Products { get; set; }
        public DbSet Items { get; set; }
    }

Step 7: Enable Migration

Go to Tools-> NuGet Package Manager -> Package Manger Console
Type the following command in package manager console to enable migration
PM> Enable-Migrations -ContextTypeName InventoryDBContext

After pressing enter you will see a class name Configuration is created in Migrations folder with some codes.
Now add seed data in Seed method of Configuration class in Migrations folder as follows.

    internal sealed class Configuration : DbMigrationsConfiguration
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
        }

        protected override void Seed(Web.Mahedee.net.Models.InventoryDBContext context)
        {
            context.Categories.AddOrUpdate(
                p => p.Name,
                new Category
                {
                    Name = "Electronics",
                    Products = new List { 
                        new Product{Name = "Mobile"},
                        new Product{Name = "Laptop"},
                        new Product{Name = "Television"},
                        new Product{Name = "Camera"}
                    }

                },

                new Category
                {
                    Name = "Men ware",
                    Products = new List 
                    { 
                        new Product{Name = "Footware"},
                        new Product{Name = "Clothings"},
                        new Product{Name = "Watches"},
                        new Product{Name = "Hand bag"},
                        new Product{Name = "Sun Glass"}
                    }
                },

                new Category
                {
                    Name = "Baby & Kids",
                    Products = new List 
                    { 
                        new Product{Name = "Baby footware"},
                        new Product{Name = "Kids clothigs"},
                        new Product{Name = "Baby care"}
                    }
                },

                 new Category
                {
                    Name = "Books",
                    Products = new List 
                    { 
                        new Product{Name = "Introduction to C#"},
                        new Product{Name = "ASP.NET MVC Begineer to Professional"},
                        new Product{Name = "ASP.NET Web API Security"},
                        new Product{Name = "SPA with ASP.NET MVC"}
                    }
                }

                );
        }
    }

Step 8: Add Migration and Update database
In package manager console write the following command to add a migration.

PM> add-migration firstmigration

A file will be created in Migrations folder something like below.
File Name: 201512041037292_firstmigration

Update the file, in AddForeignKey section and set false for cascadeDelete as follows.

   public partial class firstmigration : DbMigration
    {
        public override void Up()
        {
            DropForeignKey("dbo.Categories", "Item_Id", "dbo.Items");
            DropForeignKey("dbo.Products", "Item_Id", "dbo.Items");
            DropIndex("dbo.Categories", new[] { "Item_Id" });
            DropIndex("dbo.Products", new[] { "Item_Id" });
            CreateIndex("dbo.Items", "CategoryId");
            CreateIndex("dbo.Items", "ProductId");

            AddForeignKey("dbo.Items", "CategoryId", "dbo.Categories", "Id", cascadeDelete: false);
            AddForeignKey("dbo.Items", "ProductId", "dbo.Products", "Id", cascadeDelete: false);

            DropColumn("dbo.Categories", "Item_Id");
            DropColumn("dbo.Products", "Item_Id");
        }
        
        public override void Down()
        {
            AddColumn("dbo.Products", "Item_Id", c => c.Int());
            AddColumn("dbo.Categories", "Item_Id", c => c.Int());
            DropForeignKey("dbo.Items", "ProductId", "dbo.Products");
            DropForeignKey("dbo.Items", "CategoryId", "dbo.Categories");
            DropIndex("dbo.Items", new[] { "ProductId" });
            DropIndex("dbo.Items", new[] { "CategoryId" });
            CreateIndex("dbo.Products", "Item_Id");
            CreateIndex("dbo.Categories", "Item_Id");
            AddForeignKey("dbo.Products", "Item_Id", "dbo.Items", "Id");
            AddForeignKey("dbo.Categories", "Item_Id", "dbo.Items", "Id");
        }
    }

Write the following command in package manager console to update database.
PM> update-database –Verbose

Step 9: Add Items Controller

  • Right click on Controllers folder -> Add -> Controller
  • Select MVC 5 Controller with views using Entity Framework and the click Add

2015-12-04-04

  • Select Item as Model class and InventoryDBContext as context class and click Add button as follows

2015-12-04-05

ItemsController and Views will be created automatically.

Step 10: Update Items controller

  • Modify the following action of Items controller
        public ActionResult Create()
        {
            List lstCategory = db.Categories.ToList();
            lstCategory.Insert(0, new Category { Id = 0, Name = "--Select Category--" });

            List lstProduct = new List();
            ViewBag.CategoryId = new SelectList(lstCategory, "Id", "Name");
            ViewBag.ProductId = new SelectList(lstProduct, "Id", "Name");
            return View();
        }

  • Add the following action in the Items controller
        public JsonResult GetProductsByCategoryId(int id)
        {
            List products = new List();
            if (id > 0)
            {
                products = db.Products.Where(p => p.CategoryId == id).ToList();

            }
            else
            {
                products.Insert(0, new Product { Id = 0, Name = "--Select a category first--" });
            }
            var result = (from r in products
                          select new
                          {
                              id = r.Id,
                              name = r.Name
                          }).ToList();

            return Json(result, JsonRequestBehavior.AllowGet);
        }

Step 5: Modify the Create View of Items folder
Modify the Create View as follows.

@model Web.Mahedee.net.Models.Item

@{
    ViewBag.Title = "Create";
}




Create

@using (Html.BeginForm()) { @Html.AntiForgeryToken()

Item


@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.LabelFor(model => model.CategoryId, "Category", htmlAttributes: new { @class = "control-label col-md-2" })
@Html.DropDownList("CategoryId", null, htmlAttributes: new { @class = "form-control" }) @Html.ValidationMessageFor(model => model.CategoryId, "", new { @class = "text-danger" })
@Html.LabelFor(model => model.ProductId, "Product", htmlAttributes: new { @class = "control-label col-md-2" })
@Html.DropDownList("ProductId", null, htmlAttributes: new { @class = "form-control" }) @Html.ValidationMessageFor(model => model.ProductId, "", new { @class = "text-danger" })
@Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
@Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
}
@Html.ActionLink("Back to List", "Index")
@section Scripts { @Scripts.Render("~/bundles/jqueryval") }

Now run the application and type the following URL .

http://localhost:61767/Items/Create

You will see the following output. Now select category from category dropdown lsit, you will see product dropdown list is populating on corresponding category.

2015-12-04-06

Means, it’s working…!! Cheers!!!

Certificate Awarding Ceremony of C#.NET Applied OOP (Batch 01 to Batch 04)

Mr. Zunaid Ahmed Palak, M.P; Honorable State Minister; ICT Division, Ministry of Post, Telecommunication & Information Technology; Government of the People’s Republic of Bangladesh was graciously present as Chief Guest, and handed over the certificates to successful trainees. The ceremony was chaired by Mr. Md. Harunur Rashid, Additional Secretary, Information and Communication Technology Division. Mrs. Hosne Ara Begum ndc, Managing Director, Bangladesh Hi-Tech Park Authority and Mr. A. N. M Safiqul Islam, Project Director, Support to Development of Kaliakoir Hi-Tech Park Project were also present as Special Guests. Honorable Chairman of LEADS Group Mr. Shaikh Abdul Aziz and Honorable Managing Director of LEADS Group Mr. Shaikh A Wahed were also present at the ceremony.
The training was organized by LEADS Technology Limited and supported by Bangladesh Hi-Tech Park Authority.

Date: 24 November 2015
Venue: Bangladesh Hi-Tech Park Auditorium

Last class of C#.NET Applied OOP Training (Batch – 04)

Last class of C#.NET Applied OOP Training (Batch – 04) on 13 November 2015
Training Title: C#.NET Applied OOP
Organized by: Bangladesh Hi-Tech Park Authority (BHTPA) and Leads Technology Limited
Total Duration: 144 Hours
Trainer: Md. Mahedee Hasan

ASP.NET Application Performance Tuning and Scalability Improvement (Part – 1)

Every developers and customer wants his/her application performed well. But it is very tricky to improve performance of a web application. It’s actually depends on different parameter like HTML client, HTTP network, Web server, middle-tier components, database components, resource-management components, TCP/IP networks, and database servers. Sometimes performance of the application increases drastically, if you change a single parameter. Sometimes you have to change multiple parameters. Here are the some performance optimization tips for ASP.NET web applications which may help you to increase performance of ASP.NET Application.

Prepare release with release mode
When prepare release for deployment, select release mode instead of debug mode.

How affect in performance?

  • If you choose debug mode instead of release mode, you are creating pdb (program database – uses for debugging) files which creates extra overhead. For this reason you may face timeout problem.

Best Practice

  • Always prepare release in release mode.

Release mode

In Web.Config, Set debug=”false”
Set debug=”false” in web.config as follows after deploying your application. By default debug=”true” when you create a web application. It is necessary to set debug=”true” in development environment.

  
    
  

How affect in performance?

  • If you set debug = “true”, application requires the pdb information to be inserted into the file and that results in a comparatively larger file and hence processing will be slow.

Best Practice

  • In deployment server, set debug = “false” in web.config

Turn off Tracing unless until required
Sometimes developers need to trace the application to monitor the executions of application or a pages. It requires for application diagnostic purposes.

How affect in performance?

  • When trace is enabled it loaded extra information to the pages which degrades performances.

Best Practice

  • Always set trace enabled = “false” unless or until you required to monitor a page’s executions. Set trace enable = “false” as follows in web.config.

    

Carefully manage session state
Session state is a very useful feature of asp.net. Though, ASP.NET manages session state by default, we must pay attention of session memory management.

  • How affect in performance?
  • When you store your data in in-process or on a state server or in a SQL Database, session state, it requires memory.
  • It is also time consuming when you store or retrieve data in-process or state server or SQL server.

Best Practice

  • If your page is static, it is recommended not to use session state. In such cases where you don’t need to use session state, disable it on your web form using the following directive:
    <@%Page EnableSessionState="false"%>
  • In case you use the session state only to retrieve data and not to update, make the session state read-only using the following directive.
    <@%Page EnableSessionState ="ReadOnly"%>
  • If your application session state is out of process then consider carefully whether there is a need of the state server or SQL Server mode.
  • SQL Server session mode provides lower performance than state server mode.
  • Try to avoid keeping object in session. Since it requires serializing then de-serializing which affected in performance.
  • Use client-side state management than server side.

Disable View State of a page if not required

  • It stores data in the generated HTML using hidden field not on the server.
  • View State provides page level state management
  • As long as the user is on the current page, state is available and the user redirects to the next page and the current page state is lost
  • View State can store any type of data because it is object type but it is preferable not to store a complex type of data due to the need for serialization and deserialization on each post back

How affect in performance?

  • It increases the total payload of a page when submitted and when serving request.
  • Serialization and deserialization of the data is required when submitting data and gets requested data.
  • View state increases the memory allocations on the server.

Best Practice

  • Pages that do not have any server postback events can have the view state turned off.
  • The default behaviour of the View State property is enabled, but if you don’t need it, you can turn it off at the control or page level.
  • Within a control, simply set the EnableViewState property to false, or set it globally within the page using this setting.

    <%@ Page EnableViewState="false" %>

Use finally block to release resources
We always uses try, catch and finally block for exception handling. Finally block executes whether any exception occurs or not.
How affect in performance?

  • Sometimes application occupy resources where as it doesn’t need it. It is occur due to bad programming.

Best Practice

  • Always use a finally block to release resources like closing database connections, closing files, disposing objects and other resources.

Avoid unnecessary round trips to the server

How affect in performance?

  • Unnecessary round trips significantly effect on web application performance.
  • It increases network latency and downstream server latency.
  • Many data-driven Web sites heavily access the database for every user request. While connection pooling helps, the increased network traffic and processing load on the database server can adversely affect performance.

Best Practice

  • Keep round trips as minimum as possible
  • Use Ajax or partial page load instead of full page reload or refresh.

Choose low cost authentication
Authentication is a main factor for a secured applications. You must take decision which authentication will you use? Keep in mind, passport authentication is slower than form-base authentication which is slower than Windows authentication.

Use paging in grid view
In asp.net web application to show data in tabular format, generally we use grid view. Besides this we also uses DataGrid, JQgrid, Telerik grid, Kendo Grid etc. For huge number of data we cannot think general way because it takes huge time to load.

Best Practice

  • To load grid view faster take advantages of paging, it shows small subsets of data at a time. JQGrid is faster than asp.net grid view because it does everything in client side.

Minimizes number of web server control

How affect in performance?

  • The uses of web server controls increase the response time.
  • Web server controls go to the server executes all of its life cycle and then rendered on the client side.

Best Practice

  • Don’t use server control unless until required. Use HTML elements where suited.

Introduction to OData Services using ASP.NET Web API

What is OData?

OData Stands for Open Data Protocol. It is a data access protocol for the web. OData provides a uniform way to query and manipulate data sets through CRUD operations (create, read, update, and delete). OData consumption can be done across different Programming Language. ASP.NET Web API supports both OData v3 and V4.

Advantages of OData Services

  • OData based on REST Architecture so we can retrieve data using URL
  • Support CRUD Operation using HTTP Method like GET, POST, PUT, DELETE
  • Support HTTP, JSON and Atom Pub
  • It is very light weight, so interaction of client and server is very fast

Disadvantage

  • Since it is URL based so many people think it is less secure
  • It does not support all type of custom query

Let’s implement OData Services using ASP.NET Web API

Tools and Technology used
I used following tools and technology to develop the project –

  • Visual Studio 2013
  • Visual C#
  • ASP.NET Web API 2
  • Entity Framework 6
  • Postman(Google postman)

Step 1: Create a ASP.net Web API Project
Open visual studio and then go
File -> Project -> ASP.NET Web Application

01

Now select Web API and press OK

2

Step 2: Install Microsoft.AspNet.Odata

To install OData Nuget Pacakge from Package Manager Console.
Select Tool -> NuGet Package Manager > Package Manager Console
Type following command in package manager console

PM> Install-Package Microsoft.AspNet.Odata

Step 3: Create a model name Employee

Create a Model name Employee in model folder


    public class Employee
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Designation { get; set; }
        public string Dept { get; set; }
        public string BloodGroup { get; set; }
    }

Step 4: Change or Add Connection String
Change or Add connection string in Web.config


Step 5: Create a Context class

Create HRMContext class in Model  folder.

    public class HRMContext : DbContext
    {
        public HRMContext()
            : base("DefaultConnection")
        {
        }
        public DbSet<Employee> Employees { get; set; }
    }

Step 6: Add a Controller

Press right button on Controller folder -> Add -> Controller

Now choose “Web API 2 OData v3 Controller with actions, using Entity Framework” scaffolding template and then press Add.

3

Now choose Controller Name as EmployeeController, Model name as Employee and Context name as HRMContext and click Add like below.

04

The following code will be generated on corresponding for the controller.

    public class EmployeeController : ODataController
    {
        private HRMContext db = new HRMContext();

        // GET: odata/Employee
        [EnableQuery]
        public IQueryable<Employee> GetEmployee()
        {
            return db.Employees;
        }

        // GET: odata/Employee(5)
        [EnableQuery]
        public SingleResult<Employee> GetEmployee([FromODataUri] int key)
        {
            return SingleResult.Create(db.Employees.Where(employee => employee.Id == key));
        }

        // PUT: odata/Employee(5)
        public IHttpActionResult Put([FromODataUri] int key, Delta patch)
        {
            Validate(patch.GetEntity());

            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            Employee employee = db.Employees.Find(key);
            if (employee == null)
            {
                return NotFound();
            }

            patch.Put(employee);

            try
            {
                db.SaveChanges();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!EmployeeExists(key))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }

            return Updated(employee);
        }

        // POST: odata/Employee
        public IHttpActionResult Post(Employee employee)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            db.Employees.Add(employee);
            db.SaveChanges();

            return Created(employee);
        }

        // PATCH: odata/Employee(5)
        [AcceptVerbs("PATCH", "MERGE")]
        public IHttpActionResult Patch([FromODataUri] int key, Delta patch)
        {
            Validate(patch.GetEntity());

            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            Employee employee = db.Employees.Find(key);
            if (employee == null)
            {
                return NotFound();
            }

            patch.Patch(employee);

            try
            {
                db.SaveChanges();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!EmployeeExists(key))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }

            return Updated(employee);
        }

        // DELETE: odata/Employee(5)
        public IHttpActionResult Delete([FromODataUri] int key)
        {
            Employee employee = db.Employees.Find(key);
            if (employee == null)
            {
                return NotFound();
            }

            db.Employees.Remove(employee);
            db.SaveChanges();

            return StatusCode(HttpStatusCode.NoContent);
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }

        private bool EmployeeExists(int key)
        {
            return db.Employees.Count(e => e.Id == key) > 0;
        }
    }

Step 7: Configure OData End Point

Open the file App_Start/WebApiConfig.cs. Add the following using statements:

using System.Web.Http.OData.Builder;
using System.Web.Http.OData.Extensions;
using Web.OData.Models;

Add the following code in the register method.


    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
            builder.EntitySet("Employee");
config.Routes.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());
}
}

Step 8: Enable Migration

Type the following command in package manager console to enable migration
PM> Enable-Migrations -ContextTypeName HRMContext

After pressing enter you will see a class name Configuration is created in Mingrations folder with some codes.

Step 9: Add seed data and add migration

Modify the Seed() method of Configuration class like below to add some seed data.

        protected override void Seed(Web.OData.Models.HRMContext context)
        {

            context.Employees.AddOrUpdate(
              p => p.Name,
              new Employee { Name = "Mahedee Hasan", Designation = "Software Architect", Dept = "SSD", BloodGroup = "A+" },
              new Employee { Name = "Kazi Aminur Rashid", Designation = "AGM", Dept = "SSD", BloodGroup = "NA" },
              new Employee { Name = "Tauhidul Haque", Designation = "DGM", Dept = "SSD", BloodGroup = "A+" }
            );

}

Now type the following command in the package manager console to add a migration.

PM> Add-Migration initialmigration

Step 10: Update database and attaché mdf file

Now type the following command in package manager console.

PM> Update-Database –Verbose

You will see two file .mdf and .ldf is created in your App_data directory. Now attached the file like below.

05

Now run you application. Run Postman. Type http://localhost:64126/odata/Employee in your postbox you will see following output in JSON format. Use port number on which your application currently running instead of 64126.

06

Now, it’s working…!! Cheers!!!

First class of C#.NET Applied OOP Training (Batch – 04)

First class of C#.NET Applied OOP Training (Batch – 04) on 27August 2015
Training Title: C#.NET Applied OOP
Organized by: Bangladesh Hi-Tech Park Authority (BHTPA) and Leads Technology Limited
Total Duration: 144 Hours
Trainer: Md. Mahedee Hasan

Windows 10 Developers Day at North South University

Delivered speech on “The world of Enterprise solution development with ASP.NET and C#”
Organized by : Computer Club, North South University
Conducted by : Microsoft Most Valuable Professionals (MVP)
Powered by: Microsoft

Last class of C#.NET Applied OOP (Batch -3)


Last class of C#.NET Applied OOP by Bangladesh Hi-Tech Park Authority at Leads Technology Limited. Conducted by me, Md. Mahedee Hasan.