European ASP.NET MVC 4 and MVC 5 Hosting

BLOG about ASP.NET MVC 3, ASP.NET MVC 4, and ASP.NET MVC 5 Hosting and Its Technology - Dedicated to European Windows Hosting Customer

ASP.NET MVC Hosting - HostForLIFE.eu :: Onion Architecture In ASP.NET Core MVC

clock July 30, 2026 13:20 by author Peter

The Onion Architecture term was coined by Jeffrey Palermo in 2008. This architecture provides a better way to build applications for better testability, maintainability, and dependability on the infrastructures like databases and services. This architecture's main aim is to address the challenges faced with 3-tier architecture or n-tier architecture and to provide a solution for common problems, like coupling and separation of concerns. There are two types of coupling - tight coupling and loose coupling.

Tight Coupling
When a class is dependent on a concrete dependency, it is said to be tightly coupled to that class. A tightly coupled object is dependent on another object; that means changing one object in a tightly coupled application, often requires changes to a number of other objects. It is not difficult when an application is small but in an enterprise-level application, it is too difficult to make the changes.
 
Loose Coupling
It means two objects are independent and an object can use another object without being dependent on it. It is a design goal that seeks to reduce the interdependencies among components of a system with the goal of reducing the risk that changes in one component will require changes in any other component.
 
Advantages of Onion Architecture
There are several advantages of the Onion Architecture, as listed below.

  • It provides better maintainability as all the codes depend on layers or the center.
  • It provides better testability as the unit test can be created for separate layers without an effect of other modules of the application.
  • It develops a loosely coupled application as the outer layer of the application always communicates with the inner layer via interfaces.
  • Any concrete implantation would be provided to the application at run time
  • Domain entities are core and center part. It can have access to both the database and UI layers.
  • The internal layers never depend on the external layer. The code that may have changed should be part of an external layer.

Why Onion Architecture
There are several traditional architectures, like 3-tier architecture and n-tier architecture, all having their own pros and cons. All these traditional architectures have some fundamental issues, such as - tight coupling and separation of concerns. The Model-View-Controller is the most commonly used web application architecture, these days. It solves the problem of separation of concern as there is a separation between UI, business logic, and data access logic. The View is used to design the user interface. The Model is used to pass the data between View and Controller on which the business logic performs any operations. The Controller is used to handle the web request by action methods and returns View accordingly. Hence, it solves the problem of separation of concern while the Controller is still used to database access logic. In essence, MVC solves the separation of concern issue but the tight coupling issue still remains.
 
On the other hand, Onion Architecture addresses both the separation of concern and tight coupling issues. The overall philosophy of the Onion Architecture is to keep the business logic, data access logic, and model in the middle of the application and push the dependencies as far outward as possible means all coupling towards to center.
 
Onion Architecture Layers
This architecture relies heavily on the Dependency Inversion Principle. The UI communicates to business logic through interfaces. It has four layers, as shown in figure 1.

  • Domain Entities Layer
  • Repository Layer
  • Service Layer
  • UI (Web/Unit Test) Layer

These layers are towards to center. The center part is the Domain entities that represent the business and behavior objects. These layers can vary but the domain entities layer is always part of the center. The other layer defines more behavior of an object. Let’s see each layer one by one.

Domain Entities Layer
It is the center part of the architecture. It holds all application domain objects. If an application is developed with the ORM entity framework then this layer holds POCO classes (Code First) or Edmx (Database First) with entities. These domain entities don't have any dependencies.
 
Repository Layer
The layer is intended to create an abstraction layer between the Domain entities layer and the Business Logic layer of an application. It is a data access pattern that prompts a more loosely coupled approach to data access. We create a generic repository, which queries the data source for the data, maps the data from the data source to a business entity, and persists changes in the business entity to the data source.
 
Service Layer
The layer holds interfaces which are used to communicate between the UI layer and repository layer. It holds business logic for an entity so it’s called the business logic layer as well.
 
UI Layer
It’s the most external layer. It could be the web application, Web API, or Unit Test project. This layer has an implementation of the Dependency Inversion Principle so that the application builds a loosely coupled application. It communicates to the internal layer via interfaces.

Onion Architecture Project Structure

To implement the Onion architecture, we develop an ASP.NET Core application. This application performs CRUD operations on entities. The application holds four projects as per figure 2. Each project represents a layer in onion architecture. 

There are four projects in which three are class library projects and one is a web application project. Let’s see each project mapping with onion architecture layers.

OA.Data
It is a class library project. It holds POCO classes along with configuration classes. It represents the Domain Entities layer of the onion architecture. These classes are used to create database tables. It’s a core and central part of the application.
 
OA.Repo
It is a second class library project. It holds a generic repository class with its interface implementation. It also holds a DbContext class. The Entity Framework Code First data access approach needs to create a data access context class that inherits from the DbContext class. This project represents the Repository layer of the onion architecture.
 
OA.Service
It is a third class library project. It holds business logic and interfaces. These interfaces communicate between UI and data access logic. As it communicates via interfaces,  it builds applications that are loosely coupled. This project represents the Service layer of the onion architecture.
 
OA.Web

It is an ASP.NET Core Web application in this sample but it could be a Unit Test or Web API project. It is the most external part of an application by which the end-user can interact with the application. It builds loosely coupled applications with in-built dependency injection in ASP.NET Core. It represents the UI layer of the onion architecture.

Implement Onion Architecture
To implement the Onion Architecture in the ASP.NET Core application, create four projects as described in the above section. These four projects represent four layers of the onion architecture. Let’s see each one by one.
 
Domain Entities Layer
The Entities Domain layer is a core and central part of the architecture. So first, we create "OA.Data" project to implement this layer. This project holds POCO class and fluent API configuration for this POCO classes.
 
There is an unsupported issue of EF Core 1.0.0-preview2-final with "NETStandard.Library": "1.6.0". Thus, we have changed the target framework to netstandard1.6 > netcoreapp1.0. We modify the project.json file of OA.Data project to implement the Entity Framework Core in this class library project. Thus, the code snippet, mentioned below, is used for the project.json file after modification.
    {  
      "dependencies": {  
        "Microsoft.EntityFrameworkCore.SqlServer": "1.0.0",  
        "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final"  
      },  
      "frameworks": {  
        "netcoreapp1.0": {  
          "imports": [ "dotnet5.6", "portable-net45+win8" ]  
        }  
      },  
      "tools": {  
        "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final"  
      },  
      "version": "1.0.0-*"  
    }  


This Application uses the Entity Framework Code First approach, so the project OA.Data contains entities that are required in the application's database. The OA.Data project holds three entities, one is the BaseEntity class that has common properties that will be inherited by each entity. The code snippet, mentioned below is the BaseEntity class.
    using System;  
    using System.Collections.Generic;  
    using System.Linq;  
    using System.Threading.Tasks;  
      
    namespace OA.Data  
    {  
        public class BaseEntity  
        {  
            public Int64 Id { get; set; }  
            public DateTime AddedDate { get; set; }  
            public DateTime ModifiedDate { get; set; }  
            public string IPAddress { get; set; }  
        }  
    }  


There are two more entities, one is User and the another one is UserProfile. Both entities have a one to one relationship, as shown below. 

Now, we create an User entity, which is inherited from BaseEntity class. The code snippet, mentioned below is for the User entity.
    namespace OA.Data  
    {  
        public class User:BaseEntity  
        {  
            public string UserName { get; set; }  
            public string Email { get; set; }  
            public string Password { get; set; }  
            public virtual UserProfile UserProfile { get; set; }  
        }  
    }  

Now, we define the configuration for the User entity that will be used when the database table will be created by the entity. The following is a code snippet for the User mapping entity (UserMap.cs).
    using Microsoft.EntityFrameworkCore.Metadata.Builders;  
      
    namespace OA.Data  
    {  
        public class UserMap  
        {  
            public UserMap(EntityTypeBuilder<User> entityBuilder)  
            {  
                entityBuilder.HasKey(t => t.Id);  
                entityBuilder.Property(t => t.Email).IsRequired();  
                entityBuilder.Property(t => t.Password).IsRequired();  
                entityBuilder.Property(t => t.Email).IsRequired();  
                entityBuilder.HasOne(t => t.UserProfile).WithOne(u => u.User).HasForeignKey<UserProfile>(x => x.Id);  
            }  
        }  
    }  


Now, we create a UserProfile entity, which inherits from the BaseEntity class. The code snippet, mentioned below is for the UserProfile entity.
    namespace OA.Data  
    {  
        public class UserProfile:BaseEntity  
        {  
            public string FirstName { get; set; }  
            public string LastName { get; set; }  
            public string Address { get; set; }  
            public virtual User User { get; set; }  
        }  
    }  


Now, we define the configuration for the UserProfile entity that will be used when the database table will be created by the entity. The code snippet is mentioned below for the UserProfile mapping entity (UserProfileMap.cs).
    using Microsoft.EntityFrameworkCore.Metadata.Builders;  
      
    namespace OA.Data  
    {  
        public class UserProfileMap  
        {  
            public UserProfileMap(EntityTypeBuilder<UserProfile> entityBuilder)  
            {  
                entityBuilder.HasKey(t => t.Id);  
                entityBuilder.Property(t => t.FirstName).IsRequired();  
                entityBuilder.Property(t => t.LastName).IsRequired();  
                entityBuilder.Property(t => t.Address);    
            }  
        }  
    }  

Repository Layer
Now we create a second layer of the onion architecture which is a repository layer. To build this layer, we create one more class library project named OA.Repo. This project holds both repository and data, context classes.
 
The OA.Repo project contains DataContext. The ADO.NET Entity Framework Code First data access approach needs to create a data access context class that inherits from the DbContext class, so we create a context class ApplicationContext (ApplicationContext.cs).
 
In this class, we override the OnModelCreating() method. This method is called when the model for a context class (ApplicationContext) has been initialized, but before the model has been locked down and used to initialize the context such that the model can be further configured before it is locked down. The following is the code snippet for the context class.
    using Microsoft.EntityFrameworkCore;  
    using OA.Data;  
      
    namespace OA.Repo  
    {  
        public class ApplicationContext : DbContext  
        {  
            public ApplicationContext(DbContextOptions<ApplicationContext> options) : base(options)  
            {  
            }  
            protected override void OnModelCreating(ModelBuilder modelBuilder)  
            {  
                base.OnModelCreating(modelBuilder);  
                new UserMap(modelBuilder.Entity<User>());  
                new UserProfileMap(modelBuilder.Entity<UserProfile>());  
            }  
        }  
    }  


The DbContext must have an instance of DbContextOptions in order to execute. We will use dependency injection, so we pass options via constructor dependency injection. ASP.NET Core is designed from the ground to support and leverage dependency injection. Thus, we create generic repository interface for the entity operations, so that we can develop loosely coupled application. The code snippet, mentioned below is for the IRepository interface.
    using OA.Data;  
    using System.Collections.Generic;  
      
    namespace OA.Repo  
    {  
        public interface IRepository<T> where T : BaseEntity  
        {  
            IEnumerable<T> GetAll();  
            T Get(long id);  
            void Insert(T entity);  
            void Update(T entity);  
            void Delete(T entity);  
            void Remove(T entity);  
            void SaveChanges();  
        }  
    }  


Now, let's create a repository class to perform database operations on the entity, which implements IRepository. This repository contains a parameterized constructor with a parameter as Context, so when we create an instance of the repository, we pass a context so that the entity has the same context. The code snippet is mentioned below for the Repository class under OA.Repo project.
    using Microsoft.EntityFrameworkCore;  
    using OA.Data;  
    using System;  
    using System.Collections.Generic;  
    using System.Linq;  
      
    namespace OA.Repo  
    {  
        public class Repository<T> : IRepository<T> where T : BaseEntity  
        {  
            private readonly ApplicationContext context;  
            private DbSet<T> entities;  
            string errorMessage = string.Empty;  
      
            public Repository(ApplicationContext context)  
            {  
                this.context = context;  
                entities = context.Set<T>();  
            }  
            public IEnumerable<T> GetAll()  
            {  
                return entities.AsEnumerable();  
            }  
      
            public T Get(long id)  
            {  
                return entities.SingleOrDefault(s => s.Id == id);  
            }  
            public void Insert(T entity)  
            {  
                if (entity == null)  
                {  
                    throw new ArgumentNullException("entity");  
                }  
                entities.Add(entity);  
                context.SaveChanges();  
            }  
      
            public void Update(T entity)  
            {  
                if (entity == null)  
                {  
                    throw new ArgumentNullException("entity");  
                }  
                context.SaveChanges();  
            }  
      
            public void Delete(T entity)  
            {  
                if (entity == null)  
                {  
                    throw new ArgumentNullException("entity");  
                }  
                entities.Remove(entity);  
                context.SaveChanges();  
            }  
            public void Remove(T entity)  
            {  
                if (entity == null)  
                {  
                    throw new ArgumentNullException("entity");  
                }  
                entities.Remove(entity);              
            }  
      
            public void SaveChanges()  
            {  
                context.SaveChanges();  
            }  
        }  
    }  

We developed entity and context which are required to create a database but we will come back to this after creating the two more projects.
 
Service Layer
Now we create the third layer of the onion architecture which is a service layer. To build this layer, we create one more class library project named OA.Service. This project holds interfaces and classes which have an implementation of interfaces. This layer is intended to build loosely coupled applications. This layer communicates to both Web applications and repository projects.
 
We create an interface named IUserService. This interface holds all methods signature which accesses by external layer for the User entity. The following code snippet is for the same (IUserService.cs).
    using OA.Data;  
    using System.Collections.Generic;  
      
    namespace OA.Service  
    {  
        public  interface IUserService  
        {  
            IEnumerable<User> GetUsers();  
            User GetUser(long id);  
            void InsertUser(User user);  
            void UpdateUser(User user);  
            void DeleteUser(long id);  
        }  
    }  


Now, this IUserService interface implements on a class named UserService. This UserService class holds all the operations for User entity. The following code snippet is for the same(UserService.cs).
    using OA.Data;  
    using OA.Repo;  
    using System.Collections.Generic;  
      
    namespace OA.Service  
    {  
        public class UserService:IUserService  
        {  
            private IRepository<User> userRepository;  
            private IRepository<UserProfile> userProfileRepository;  
      
            public UserService(IRepository<User> userRepository, IRepository<UserProfile> userProfileRepository)  
            {  
                this.userRepository = userRepository;  
                this.userProfileRepository = userProfileRepository;  
            }  
      
            public IEnumerable<User> GetUsers()  
            {  
                return userRepository.GetAll();  
            }  
      
            public User GetUser(long id)  
            {  
                return userRepository.Get(id);  
            }  
      
            public void InsertUser(User user)  
            {  
                userRepository.Insert(user);  
            }  
            public void UpdateUser(User user)  
            {  
                userRepository.Update(user);  
            }  
      
            public void DeleteUser(long id)  
            {              
                UserProfile userProfile = userProfileRepository.Get(id);  
                userProfileRepository.Remove(userProfile);  
                User user = GetUser(id);  
                userRepository.Remove(user);  
                userRepository.SaveChanges();  
            }  
        }  
    }  

We create one more interface named IUserProfileService. This interface holds method signature which is accessed by the external layer for the UserProfile entity. The following code snippet is for the same (IUserProfileService.cs).
    using OA.Data;  
      
    namespace OA.Service  
    {  
        public interface IUserProfileService  
        {  
            UserProfile GetUserProfile(long id);  
        }  
    }  


Now, this IUserProfileService interface implements on a class named UserProfileService. This UserProfileService class holds the operation for UserProfile entity. The following code snippet is for the same(UserProfileService.cs).
    using OA.Data;  
    using OA.Repo;  
      
    namespace OA.Service  
    {  
        public class UserProfileService: IUserProfileService  
        {  
            private IRepository<UserProfile> userProfileRepository;  
      
            public UserProfileService(IRepository<UserProfile> userProfileRepository)  
            {             
                this.userProfileRepository = userProfileRepository;  
            }  
      
            public UserProfile GetUserProfile(long id)  
            {  
                return userProfileRepository.Get(id);  
            }  
        }  
    }  

UI Layer

Now, we create the external layer of the onion architecture which is a UI layer. The end-user interacts with the application by this layer. To build this layer, we create an ASP.NET Core MVC web application named OA.Web. This layer communicates with service layer projects. This project contains the user interface for both user and user profile entities database operations and the controller to do these operations.
 
As the concept of dependency injection is central to the ASP.NET Core application, we register context, repository, and service to the dependency injection during the application start up. Thus, we register these as a Service in the ConfigureServices method in the StartUp class as per the following code snippet.
    public void ConfigureServices(IServiceCollection services)  
          {             
              services.AddMvc();  
              services.AddDbContext<ApplicationContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));  
              services.AddScoped(typeof(IRepository<>), typeof(Repository<>));  
              services.AddTransient<IUserService, UserService>();  
              services.AddTransient<IUserProfileService, UserProfileService>();  
          }  

Here, the DefaultConnection is connection string which defined in appsettings.json file as per following code snippet.

    {  
      "ConnectionStrings": {  
        "DefaultConnection": "Data Source=DESKTOP-RG33QHE;Initial Catalog=OADb;User ID=sa; Password=***"  
      },  
      "Logging": {  
        "IncludeScopes": false,  
        "LogLevel": {  
          "Default": "Debug",  
          "System": "Information",  
          "Microsoft": "Information"  
        }  
      }  
    }  

Now, we have configured settings to create a database, so we have time to create a database, using migration. We must choose the OA.Repo project in the Package Manager console during the performance of the steps, mentioned below.

  • Tools -> NuGet Package Manager -> Package Manager Console
  • Run PM> Add-Migration MyFirstMigration to scaffold a migration to create the initial set of tables for our model. If we receive an error stating the term `add-migration' is not recognized as the name of a cmdlet, then close and reopen Visual Studio.
  • Run PM> Update-Database to apply the new migration to the database. Because our database doesn't exist yet, it will be created for us before the migration is applied.

Create Application User Interface
Now, we proceed to the controller. We create a controller named UserController under the Controllers folder of the application. It has all ActionResult methods for the end-user interface of operations. We create both IUserService and IUserProfile interface instances; then we inject these in the controller's constructor to get its object. The following is a partial code snippet for the UserController in which service interfaces are injected, using constructor dependency injection.
    using System;  
    using System.Collections.Generic;  
    using System.Linq;  
    using Microsoft.AspNetCore.Mvc;  
    using OA.Service;  
    using OA.Web.Models;  
    using OA.Data;  
    using Microsoft.AspNetCore.Http;  
      
    namespace OA.Web.Controllers  
    {  
        public class UserController : Controller  
        {  
            private readonly IUserService userService;  
            private readonly IUserProfileService userProfileService;  
      
            public UserController(IUserService userService, IUserProfileService userProfileService)  
            {  
                this.userService = userService;  
                this.userProfileService = userProfileService;  
            }  
        }  
    }  


We can notice that Controller takes both IUserService and IUserProfileService as a constructor parameters. The ASP.NET Core dependency injection will take care of passing an instance of these services into UserController. The controller is developed to handle operations requests for both User and UserProfile entities. Now, let's develop the user interface for the User Listing, Add User, Edit User and Delete User. Let's see each one by one.
 
User List View
This is the first view when the application is accessed or the entry point of the application is executed. It shows the author listing as in Figure 4. The user data is displayed in a tabular format and on this view, it has linked to add a new user, edit a user and delete a user.
 
To pass data from controller to view, create named UserViewModel view model, as per the code snippet, mentioned below. This view model is also used for adding or editing a user.
    using Microsoft.AspNetCore.Mvc;  
    using System;  
    using System.ComponentModel.DataAnnotations;  
      
    namespace OA.Web.Models  
    {  
        public class UserViewModel  
        {  
            [HiddenInput]  
            public Int64 Id { get; set; }  
            [Display(Name = "First Name")]  
            public string FirstName { get; set; }  
            [Display(Name = "Last Name")]  
            public string LastName { get; set; }  
            public string Name { get; set; }  
            public string Address { get; set; }  
            [Display(Name = "User Name")]  
            public string UserName { get; set; }  
            public string Email { get; set; }  
            public string Password { get; set; }  
            [Display(Name = "Added Date")]  
            public DateTime AddedDate { get; set; }  
        }  
    }  

Now, we create action method, which returns an index view with the data. The code snippet of Index action method in UserController is mentioned below.
    [HttpGet]  
            public IActionResult Index()  
            {  
                List<UserViewModel> model = new List<UserViewModel>();  
                userService.GetUsers().ToList().ForEach(u =>  
                {  
                    UserProfile userProfile = userProfileService.GetUserProfile(u.Id);  
                    UserViewModel user = new UserViewModel  
                    {  
                        Id = u.Id,  
                        Name = $"{userProfile.FirstName} {userProfile.LastName}",  
                        Email = u.Email,  
                        Address = userProfile.Address  
                    };  
                    model.Add(user);  
                });  
      
                return View(model);  
            }  

Now, we create an index view, as per the code snippet, mentioned below under the User folder of views.
    @model IEnumerable<UserViewModel>  
    @using OA.Web.Models  
    @using OA.Web.Code  
      
    <div class="top-buffer"></div>  
    <div class="panel panel-primary">  
        <div class="panel-heading panel-head">Users</div>  
        <div class="panel-body">  
            <div class="btn-group">  
                <a id="createEditUserModal" data-toggle="modal" asp-action="AddUser" data-target="#modal-action-user" class="btn btn-primary">  
                    <i class="glyphicon glyphicon-plus"></i>  Add User  
                </a>  
            </div>  
            <div class="top-buffer"></div>  
            <table class="table table-bordered table-striped table-condensed">  
                <thead>  
                    <tr>  
                        <th>Name</th>  
                        <th>Email</th>  
                        <th>Address</th>  
                        <th>Action</th>  
                    </tr>  
                </thead>  
                <tbody>  
                    @foreach (var item in Model)  
                    {  
                        <tr>  
                            <td>@Html.DisplayFor(modelItem => item.Name)</td>  
                            <td>@Html.DisplayFor(modelItem => item.Email)</td>  
                            <td>@Html.DisplayFor(modelItem => item.Address)</td>  
                            <td>  
                                <a id="editUserModal" data-toggle="modal" asp-action="EditUser" asp-route-id="@item.Id" data-target="#modal-action-user"  
                                   class="btn btn-info">  
                                    <i class="glyphicon glyphicon-pencil"></i>  Edit  
                                </a>                           
                                <a id="deleteUserModal" data-toggle="modal" asp-action="DeleteUser" asp-route-id="@item.Id" data-target="#modal-action-user" class="btn btn-danger">  
                                    <i class="glyphicon glyphicon-trash"></i>  Delete  
                                </a>  
                            </td>  
                        </tr>  
                    }  
                </tbody>  
            </table>  
        </div>  
    </div>  
      
    @Html.Partial("_Modal", new BootstrapModel { ID = "modal-action-user", AreaLabeledId = "modal-action-user-label", Size = ModalSize.Large })  
      
    @section scripts  
    {  
        <script src="~/js/user-index.js" asp-append-version="true"></script>  
    }  

It shows all forms in the Bootstrap model popup so create the user - index.js file as per the following code snippet.

    (function ($) {  
    function User() {  
    var $this = this;  
      
    function initilizeModel() {  
    $("#modal-action-user").on('loaded.bs.modal', function (e) {  
      
    }).on('hidden.bs.modal', function (e) {  
    $(this).removeData('bs.modal');  
    });  
    }  
    $this.init = function () {  
    initilizeModel();  
    }  
    }  
    $(function () {  
    var self = new User();  
    self.init();  
    })  
    }(jQuery))  

When the application runs and calls the index() action method from UserController with a HttpGet request, it gets all the users listed in the UI, as shown in Figure 4. 

Add User 
To pass the data from UI to the controller to add a user, use the same view model named UserViewModel. The AuthorController has an action method named AddUser which returns the view to add a user. The code snippet mentioned below is for the same action method for both GET and Post requests.
    [HttpGet]  
            public ActionResult AddUser()  
            {  
                UserViewModel model = new UserViewModel();  
      
                return PartialView("_AddUser", model);  
            }  
      
            [HttpPost]  
            public ActionResult AddUser(UserViewModel model)  
            {  
                User userEntity = new User  
                {  
                    UserName = model.UserName,  
                    Email = model.Email,  
                    Password = model.Password,  
                    AddedDate = DateTime.UtcNow,  
                    ModifiedDate = DateTime.UtcNow,  
                    IPAddress = Request.HttpContext.Connection.RemoteIpAddress.ToString(),  
                    UserProfile = new UserProfile  
                    {  
                        FirstName = model.FirstName,  
                        LastName = model.LastName,  
                        Address = model.Address,  
                        AddedDate = DateTime.UtcNow,  
                        ModifiedDate = DateTime.UtcNow,  
                        IPAddress = Request.HttpContext.Connection.RemoteIpAddress.ToString()  
                    }  
                };  
                userService.InsertUser(userEntity);  
                if (userEntity.Id > 0)  
                {  
                    return RedirectToAction("index");  
                }  
                return View(model);  
            }  


The GET request for the AddUser action method returns _AddUser partial view; the code snippet follows under the User folder of views.
    @model UserViewModel  
    @using OA.Web.Models  
      
    <form asp-action="AddUser" role="form">  
        @await Html.PartialAsync("_ModalHeader", new ModalHeader { Heading = "Add User" })  
        <div class="modal-body form-horizontal">  
            <div class="row">  
                <div class="col-lg-6">  
                    <div class="form-group">  
                        <label asp-for="FirstName" class="col-lg-3 col-sm-3 control-label"></label>  
                        <div class="col-lg-6">  
                            <input asp-for="FirstName" class="form-control" />  
                        </div>  
                    </div>  
                    <div class="form-group">  
                        <label asp-for="LastName" class="col-lg-3 col-sm-3 control-label"></label>  
                        <div class="col-lg-6">  
                            <input asp-for="LastName" class="form-control" />  
                        </div>  
                    </div>  
                    <div class="form-group">  
                        <label asp-for="Email" class="col-lg-3 col-sm-3 control-label"></label>  
                        <div class="col-lg-6">  
                            <input asp-for="Email" class="form-control" />  
                        </div>  
                    </div>  
                </div>  
                <div class="col-lg-6">  
                    <div class="form-group">  
                        <label asp-for="UserName" class="col-lg-3 col-sm-3 control-label"></label>  
                        <div class="col-lg-6">  
                            <input asp-for="UserName" class="form-control" />  
                        </div>  
                    </div>  
                    <div class="form-group">  
                        <label asp-for="Password" class="col-lg-3 col-sm-3 control-label"></label>  
                        <div class="col-lg-6">  
                            <input type="password" asp-for="Password" class="form-control" />  
                        </div>  
                    </div>  
                    <div class="form-group">  
                        <label asp-for="Address" class="col-lg-3 col-sm-3 control-label"></label>  
                        <div class="col-lg-6">  
                            <input asp-for="Address" class="form-control" />  
                        </div>  
                    </div>  
                </div>  
            </div>  
        </div>  
        @await Html.PartialAsync("_ModalFooter", new ModalFooter { })  
    </form>  


When the application runs and you click on the Add User button, it makes a GET request for the AddUser() action; add a user screen, as shown in Figure 5. 

Edit User
To pass the data from UI to a controller to edit a user, use same view model named UserViewModel. The UserController has an action method named EditUser, which returns the view to edit a user. The code snippet mentioned below is  for the same action method for both GET and Post requests.
    public ActionResult EditUser(int? id)  
          {  
              UserViewModel model = new UserViewModel();  
              if (id.HasValue && id != 0)  
              {  
                  User userEntity = userService.GetUser(id.Value);  
                  UserProfile userProfileEntity = userProfileService.GetUserProfile(id.Value);  
                  model.FirstName = userProfileEntity.FirstName;  
                  model.LastName = userProfileEntity.LastName;  
                  model.Address = userProfileEntity.Address;  
                  model.Email = userEntity.Email;  
              }  
              return PartialView("_EditUser", model);  
          }  
      
          [HttpPost]  
          public ActionResult EditUser(UserViewModel model)  
          {  
              User userEntity = userService.GetUser(model.Id);  
              userEntity.Email = model.Email;  
              userEntity.ModifiedDate = DateTime.UtcNow;  
              userEntity.IPAddress = Request.HttpContext.Connection.RemoteIpAddress.ToString();  
              UserProfile userProfileEntity = userProfileService.GetUserProfile(model.Id);  
              userProfileEntity.FirstName = model.FirstName;  
              userProfileEntity.LastName = model.LastName;  
              userProfileEntity.Address = model.Address;  
              userProfileEntity.ModifiedDate = DateTime.UtcNow;  
              userProfileEntity.IPAddress = Request.HttpContext.Connection.RemoteIpAddress.ToString();  
              userEntity.UserProfile = userProfileEntity;  
              userService.UpdateUser(userEntity);  
              if (userEntity.Id > 0)  
              {  
                  return RedirectToAction("index");  
              }  
              return View(model);  
          }  


The GET request for the EditUser action method returns _EditUser partial view, where code snippet follows under the User folder of views.
    @model UserViewModel  
    @using OA.Web.Models  
      
    <form asp-action="EditUser" role="form">  
        @await Html.PartialAsync("_ModalHeader", new ModalHeader { Heading = "Edit User" })  
        <div class="modal-body form-horizontal">  
            <div class="row">              
                <input asp-for="Id" />  
                    <div class="form-group">  
                        <label asp-for="FirstName" class="col-lg-3 col-sm-3 control-label"></label>  
                        <div class="col-lg-6">  
                            <input asp-for="FirstName" class="form-control" />  
                        </div>  
                    </div>  
                    <div class="form-group">  
                        <label asp-for="LastName" class="col-lg-3 col-sm-3 control-label"></label>  
                        <div class="col-lg-6">  
                            <input asp-for="LastName" class="form-control" />  
                        </div>  
                    </div>  
                    <div class="form-group">  
                        <label asp-for="Email" class="col-lg-3 col-sm-3 control-label"></label>  
                        <div class="col-lg-6">  
                            <input asp-for="Email" class="form-control" />  
                        </div>  
                    </div>           
                
                    <div class="form-group">  
                        <label asp-for="Address" class="col-lg-3 col-sm-3 control-label"></label>  
                        <div class="col-lg-6">  
                            <input asp-for="Address" class="form-control" />  
                        </div>  
                    </div>  
                  
            </div>  
        </div>  
        @await Html.PartialAsync("_ModalFooter", new ModalFooter { })  
    </form>  


When the application runs and you click on the Edit button in the User listing, it makes a GET request for the EditUser() action, then the edit user screen is shown in Figure 6. 

 

Delete User
The UserController has an action method named DeleteUser, which returns view to delete a user. The code snippet mentioned below is for the same action method for both GET and Post requests.
    [HttpGet]  
            public PartialViewResult DeleteUser(int id)  
            {  
                UserProfile userProfile = userProfileService.GetUserProfile(id);  
                string name = $"{userProfile.FirstName} {userProfile.LastName}";  
                return PartialView("_DeleteUser", name);  
            }  
      
            [HttpPost]  
            public ActionResult DeleteUser(long id, FormCollection form)  
            {  
                userService.DeleteUser(id);            
                return RedirectToAction("Index");  
            }  

The GET request for the DeleteUser action method returns _DeleteUser partial View. The code snippet mentioned below is under the User folder of Views.
    @using OA.Web.Models  
      
    <form asp-action="DeleteUser" role="form">  
        @Html.Partial("_ModalHeader", new ModalHeader { Heading = "Delete User" })  
      
        <div class="modal-body form-horizontal">  
            Are you want to delete @Model?  
        </div>  
        @Html.Partial("_ModalFooter", new ModalFooter { SubmitButtonText = "Delete" })  
    </form>  


When the application runs and the user clicks on the "Delete" button in the user listing, it makes a GET request for the
 
DeleteUser() action, then the delete user screen is shown, as below.



Conclusion
This article introduced Onion Architecture in ASP.NET Core, using Entity Framework Core with the "code first" development approach. It’s widely accepted architecture these days. We used Bootstrap, CSS, and JavaScript for the user interface design in this application. 



ASP.NET MVC Hosting - HostForLIFE.eu :: MVC and Entity Framework-Based Server-Side Processing with Custom Range Filtering

clock July 22, 2026 11:47 by author Peter

This lesson will teach us how to use jQuery DataTables to accomplish server-side processing with custom range filtering. I will demonstrate the server-side paging, sorting, and filtering of a DataTable in an ASP.NET MVC application. Server-side refers to the use of C# code in the Controller section behind the file. To create custom multicolumn server-side filtering in jQuery DataTables, we may remove the global search box and use our own filter area with input fields like textbox and dropdown. This allows us to deal with jQuery DataTables by implementing our own filter sections wherever on our site.

With capabilities like pagination, searching, state saving, multi-column sorting with data type recognition, and much more, DataTable is the most potent and user-friendly jQuery plugin for presenting tabular data with ZERO or minimum configuration.

The following technologies must be understood in order to read this article.

The prerequisites of this article include knowledge of the following technologies.

  • ASP.NET MVC
  • HTML
  • JavaScript
  • AJAX
  • CSS
  • Bootstrap
  • C# Programming
  • C# LINQ
  • jQuery

Note. Before going through the session, I suggest you first visit my previous articles with a back-end section.

    Retrieve Records In jQuery Datatable Using Entity Framework And Bootstrap
    Performance Issue In jQuery DataTable About Fetching Records And Steps To Fix It

Steps to be followed
Step 1. Add a new action into the Controller to get the View where we will implement the jQuery DataTable with server-side paging and sorting.
Code
public ActionResult Filter()
{
    return View();
}

Step 2. Add a View for the action (here "filter") and design.

Code
@{
    ViewBag.Title = "HFL - Filter Records";
}
<h2 style="color: blue
">HFL-Server Side Processing With Custom Range Filtering</h2>
<style>
    table {
        font-family: arial, sans-serif;
        border-collapse: collapse;
        width: 100%;
    }
    td, th {
        border: 1px solid #dddddd
;
        text-align: left;
        padding: 8px;
    }
    tr:nth-child(even) {
        background-color: #dddddd
;
    }
    .custom-loader-color {
        color: #fff 
!important;
        font-size: 40px !important;
    }
    .custom-loader-background {
        background-color: #f60 
!important;
    }
    .custom-middle-align {
        vertical-align: middle !important;
    }
</style>
<div style="width:90%; margin:0 auto">
    <div style="background-color:#f5f5f5
; padding:20px">
        <h2 style="color: blue
">Filter Records</h2>
        <table>
            <tbody>
                <tr>
                    <td style="color: blue
">City</td>
                    <td><input type="text" class="form-control" id="txtCity" /></td>
                    <td style="color: blue
">State</td>
                    <td>
                        <select id="ddState" class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
                            <option value="">All States</option>
                            <option value="Karnataka">Karnataka</option>
                            <option value="Andhra Pradesh">Andhra Pradesh</option>
                            <option value="Georgia">Georgia</option>
                            <option value="Uttar Pradesh">Uttar Pradesh</option>
                            <option value="Odisha">Odisha</option>
                        </select>
                    </td>
                    <td>
                        <input type="button" class="btn btn-success btn-md" value="Filter" id="btnFilter" />
                    </td>
                </tr>
            </tbody>
        </table>
    </div>
    @* jQuery DataTables *@
    <div style="width:90%; margin:0 auto;">
        <table id="myTable" class="table table-responsive table-striped">
            <thead>
                <tr>
                    <th style="background-color: Yellow
;color: blue
">First Name</th>
                    <th style="background-color: Yellow
;color: blue
">Last Name</th>
                    <th style="background-color: Yellow
;color: blue
">Age</th>
                    <th style="background-color: Yellow
;color: blue
">Address</th>
                    <th style="background-color: Yellow
;color: blue
">City</th>
                    <th style="background-color: Yellow
;color: blue
">State</th>
                </tr>
            </thead>
        </table>
    </div>
</div>
@* Load bootstrap datatable css *@
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.1/css/bootstrap.css" rel="stylesheet" />
<link href="//cdn.datatables.net/1.10.19/css/dataTables.bootstrap4.min.css" rel="stylesheet" />
@* Load bootstrap datatable js and initialize DataTable *@
@section Scripts {
    <script src="//code.jquery.com/jquery-3.3.1.js"></script>
    <script src="//cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
    <script src="//cdn.datatables.net/1.10.19/js/dataTables.bootstrap4.min.js"></script>
    <script>
        $(document).ready(function () {
            // jQuery DataTables initialization
            $('#myTable').DataTable({
                "language": {
                    "processing": "<div class='overlay custom-loader-background'><i class='fa fa-cog fa-spin custom-loader-color'></i></div>"
                },
                "processing": true,
                "serverSide": true,
                "orderMulti": false,
                "dom": '<"top"i>rt<"bottom"lp><"clear">',
                "ajax": {
                    "url": "/home/FilterData",
                    "type": "POST",
                    "datatype": "json"
                },
                "columns": [
                    { "data": "FirstName", "name": "FirstName", "autoWidth": true },
                    { "data": "LastName", "name": "LastName", "autoWidth": true },
                    { "data": "Age", "name": "Age", "autoWidth": true },
                    { "data": "Address", "name": "Address", "autoWidth": true },
                    { "data": "City", "name": "City", "autoWidth": true },
                    { "data": "State", "name": "State", "autoWidth": true }
                ]
            });

            // DataTables filtering on button click
            var oTable = $('#myTable').DataTable();
            $('#btnFilter').click(function () {
                oTable.columns(4).search($('#txtCity').val().trim());
                oTable.columns(5).search($('#ddState').val().trim());
                oTable.draw();
            });
        });
    </script>
}


Markup
Code description

Here, I have added a textbox for City and a dropdown for State to filter the records. I used some static records in the dropdown for basic understanding and in my next session, I will fill the dropdown from the database using Entity Framework.

<div style="background-color:#f5f5f5
; padding:20px;">
    <h2 style="color: blue
;">Filter Records</h2>
    <table>
        <tbody>
            <tr>
                <td style="color: blue
;">City</td>
                <td><input type="text" class="form-control" id="txtCity" /></td>
                <td style="color: blue
;">State</td>
                <td>
                    <select id="ddState" class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
                        <option value="">All States</option>
                        <option value="
London">London</option>
                        <option value="
Manchester">Manchester</option>
                        <option value="
Liverpool">Liverpool</option>
                        <option value="
Birmingham">Birmingham</option>
                        <option value="York">York</option>
                    </select>
                </td>
                <td>
                    <input type="button" class="btn btn-success btn-md" value="Filter" id="btnFilter" />
                </td>
            </tr>
        </tbody>
    </table>
</div>


I have updated the code to implement custom multicolumn server-side filtering in jQuery DataTables by removing the default global search box. This initialization variable allows you to specify where in the DOM you want DataTables to introduce the various controls it composes to the page.
    <"top"i> means it is showing the info of entries.
    rt means it is showing the progress bar with loading records in DataTable.
    <"bottom"lp> means it is showing the length of records and also, the paging in the page.
    <"clear"> means it clears the controls or any data inside div element.

    "dom": '<"top"i>rt<"bottom"lp><"clear">'

The following piece of code will enable the data loading from server-side. The path "/home/FilterData" is the function that will be returning data from server side. The columns here are the exact names of the properties that we have created in the table and uploaded using the Entity Data Model file. Here, we can get the index number of the table's columns.
$('#myTable').DataTable({
    "language": {
        "processing": "<div class='overlay custom-loader-background'><i class='fa fa-cog fa-spin custom-loader-color'></i></div>"
    },
    "processing": true,
    "serverSide": true,
    "orderMulti": false,
    "dom": '<"top"i>rt<"bottom"lp><"clear">',
    "ajax": {
        "url": "/home/FilterData",
        "type": "POST",
        "datatype": "json"
    },
    "columns": [
        { "data": "FirstName", "name": "FirstName", "autoWidth": true }, //index 0
        { "data": "LastName", "name": "LastName", "autoWidth": true }, //index 1
        { "data": "Age", "name": "Age", "autoWidth": true }, //index 2
        { "data": "Address", "name": "Address", "autoWidth": true }, //index 3
        { "data": "City", "name": "City", "autoWidth": true }, //index 4
        { "data": "State", "name": "State", "autoWidth": true } //index 5
    ]
});


The following piece of code is used to apply custom search on jQuery DataTables. I have applied search for the city name using DataTable column index 4 and search for state name using DataTable column index 5.
oTable = $('#myTable').DataTable();
$('#btnFilter').click(function () {
    oTable.columns(4).search($('#txtCity').val().trim());
    oTable.columns(5).search($('#ddState').val().trim());
    oTable.draw();
});
});

Step 3. Add another action (here "FilterData") for fetching the data from the database and implementing the logic for server-side paging and sorting.

Code
[HttpPost]
public ActionResult FilterData()
{
    // Initialization.
    JsonResult result = new JsonResult();
    try
    {
        var draw = Request.Form.GetValues("draw").FirstOrDefault();
        var start = Request.Form.GetValues("start").FirstOrDefault();
        var length = Request.Form.GetValues("length").FirstOrDefault();
        var sortColumn = Request.Form.GetValues("columns[" + Request.Form.GetValues("order[0][column]").FirstOrDefault()
                        + "][name]").FirstOrDefault();
        var sortColumnDir = Request.Form.GetValues("order[0][dir]").FirstOrDefault();
        var city = Request.Form.GetValues("columns[4][search][value]").FirstOrDefault();
        var state = Request.Form.GetValues("columns[5][search][value]").FirstOrDefault();
        int pageSize = length != null ? Convert.ToInt32(length) : 0;
        int skip = start != null ? Convert.ToInt16(start) : 0;
        int recordsTotal = 0;
        using (HFLDBEntities dc = new HFLDBEntities())
        {
            var v = (from a in dc.employees select a);

            if (!string.IsNullOrEmpty(city))
            {
                v = v.Where(a => a.City.Contains(city));
            }
            if (!string.IsNullOrEmpty(state))
            {
                v = v.Where(a => a.State == state);
            }
            if (!(string.IsNullOrEmpty(sortColumn) && string.IsNullOrEmpty(sortColumnDir)))
            {
                v = v.OrderBy(sortColumn + " " + sortColumnDir);
            }
            recordsTotal = v.Count();
            var data = v.Skip(skip).Take(pageSize).ToList();

            return Json(new { draw = draw, recordsFiltered = recordsTotal, recordsTotal = recordsTotal, data = data },
                        JsonRequestBehavior.AllowGet);
        }
    }
    catch (Exception ex)
    {
        // Handle exception (log or display error)
        Console.WriteLine(ex); // Log exception details to console
    }
    // Return empty or default result if exception occurs
    return result;
}


Code description

I have described the code using the comment line in every line of code. It will be easy for a quick understanding of the code flow. In this piece of code, which is based on searching, sorting, and pagination information sent from the DataTable plugin, the following has been done: The data is being loaded first. It is being churned out based on the search criteria. Data is then sorted by a provided column in a provided order. Lastly, it is paginated and returned.

I have declared two variables which contain the informaion of two columns for filtering records with their index values as I have described in the View section.
var city = Request.Form.GetValues("columns[4][search][value]").FirstOrDefault();
var state = Request.Form.GetValues("columns[5][search][value]").FirstOrDefault();


The following is the piece of code for filtering records using city and state columns.
if (!string.IsNullOrEmpty(city))
{
    v = v.Where(a => a.City.Contains(city));
}
if (!string.IsNullOrEmpty(state))
{
    v = v.Where(a => a.State == state);
}


For sorting, we need to add a reference of System.Linq.Dynamic.
if (!(string.IsNullOrEmpty(sortColumn) && string.IsNullOrEmpty(sortColumnDir)))
{
    v = v.OrderBy(sortColumn + " " + sortColumnDir);
}


Output
During the initial load, the processing loader will look like below.

All states
Filter records using state dropdown, as shown below.



Filter records using city textbox.

Filter records using both, City and State.

Summary
In this write-up, we have learned how to

  • Filter records using custom multicolumn server-side features.
  • Remove default global search box of jQuery DataTable by using initialisation variable in DOM.
  • Get record's length, sorting and pagination information with the DataTable plugin.
  • Get Server-side integration of DataTable plugin with ASP.NET MVC 5.


ASP.NET MVC Hosting - HostForLIFE.eu :: Session Timeouts Causes and Remedies

clock June 24, 2026 09:29 by author Peter

For a while now, I have been investigating ASP.Net Session Timeouts. Those of you who work on web applications have undoubtedly seen unexpected timeouts that cause the application to restart abruptly; frequently, these timeouts seem to happen for no obvious reason.

Here, I offer a quick checklist that could be useful when addressing such problems.

Causes for Session Timeout could vary from:

  • Modification in Machine.Config, Web.Config or Global.asax files
  • Application's bin directory or its contents modified 
  • Antivirus is running on the  .config /.aspx files
  • The number of re-compilations (aspx, ascx or asax) exceeds the limit specified by the <compilation numRecompilesBeforeAppRestart=/> setting in machine.config or web.config  (by default this is set to 15) 
  • The physical path of the virtual directory is modified 
  • The CAS policy is modified
  • Sub-Directories of Application are deleted or renamed

New to ASP.Net 2.0  -The 7th point of Sub directories.  i.e. Whenever you delete or rename a sub-directory of your application, the application domain is recycled, terminating all users' sessions (and the cache, etc). This is a big performance hit. This behavior affects dramatically sites that allow document publishing, to the point where they stop functioning. Imagine a situation where a request creates a thread that goes through sub-directories of the application and deletes / renames them - without knowing about this 2.0 application domain recycling policy, chances are that the worker thread in question will not complete because the domain is recycled and the thread aborted. 

Huge Performance Hit
Above results in recycling of Application Domain. At the next request all assemblies need to be reloaded, the cache including any in-proc session variables etc. are empty causing a big performance hit for the application.
 
Remedies/ solutions
App domain restarts

If you suspect app domain restarts (i.e. your sessions seem to expire without obvious reasons), you will be interested to know when the restarts happen and what's causing them.

In ASP.Net 2.0 add the following element in global web.config file (C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG) as a child of the <healthMonitoring><rules> elements:
<healthMonitoring>

      <rules>

<add name="Application Lifetime Events Default"  eventName="Application Lifetime Events"

provider="EventLogProvider"  profile="Default"  minInstances="1" maxLimit="Infinite"

                  minInterval="00:01:00"  custom="" />

       </rules>

</healthMonitoring>

This will log system events that provide the time and the reason of the restart (such as: Application is shutting down. Reason: Configuration changed.)
In ASP.Net 1.1, see

If the timeout error message reads as follows:
"System.Web.HttpException: Request timed out."

Check for  <httpRuntime executionTimeout/> in appication's Web.config file
executionTimeout - Specifies the maximum number of seconds that a request is allowed to execute before being automatically shut down by ASP.NET.

You can change this setting in machine.config to affect all applications on your site, or you can override the settings in your application-specific web.config as follows: 
<system.web>

     <httpRuntime executionTimeout="900" />
</system.web>

Note: This time-out applies only if the debug attribute in the compilation element is False. If the debug attribute is True, to help avoiding application shut-down while you are debugging, do not set this time-out to a large value.

The default values in seconds
In the .NET Framework 2.0 = 110.
In the .NET Framework 1.0 and 1.1= 90.

 
Set the Session timeout in IIS Manager in default website also.
Go to IIS Manager, right click on the virtual directory and choose properties.
Now go to virtual directory tab, click Configuration button.
A dialog box will appears. Choose AppOptions tab. Set the session timeout that u need. This will solve the problem. If you are getting the same problem again then set the same thing for Default WebSite also.
 
Remove the session timeout check in IIS, then the timeout will be read from the web.config.
 
Add following code in the web.config of your application file under <system.web>
<sessionState cookieless="false" timeout="330"/>
 

For random session timeouts, timeout occurring before the value set in sessionstate and idle timeouts, check if the application pool in IIS 6.0 has any 'Memory recycling' values selected and they are set up to some low sizes both for virtual or used memoray. 

Ex-If 200 Mb is set and the application reaches this limit in 5 minutes, the recycle happens and any sessions will be thus killed sooner than expected. See the figure below



ASP.NET MVC Hosting - HostForLIFE.eu :: ASP.NET Core MVC Human Resource Management System

clock June 17, 2026 09:01 by author Peter

Systems for managing human resources (HRMS) are crucial for contemporary businesses. They automate hiring, payroll, personnel records, and attendance. The open-source HRM project shows how to use SQL Server, Entity Framework Core, and ASP.NET Core MVC to create a comprehensive HRMS.

Step 1: Environment Setup

  • Install Visual Studio 2022 with ASP.NET workload.
  • Install SQL Server and SSMS.
  • Clone the repository
  • Open the solution in Visual Studio.
Step 2: Database Configuration
  • Update appsettings.json with your SQL Server connection string.
  • Run EF Core migrations:
Update-Database
  • This creates tables like AspNetUsers, AspNetRoles, Companies, Departments, Designations.

Step 3: Authentication & Roles
  • The project uses ASP.NET Identity.
  • Roles: Admin, HR, Manager, Employee.
  • Login page: /Identity/Account/Login.
  • Debugging tip: Place a breakpoint in Login.cshtml.cs → OnPostAsync() to inspect validation.
Step 4: Admin Module
  • Dashboard → Overview of employees, departments, payroll.
  • Companies → CRUD for company records.
  • Departments → CRUD linked to companies.
  • Designations → CRUD linked to companies.
  • Role Management → Assign roles to users.
Step 5: HR Module
  • Employee Management → Add, edit, delete employees.
  • Attendance → Mark daily attendance.
  • Leave Requests → Approve/reject employee leave.
  • Recruitment → Generate offer letters, onboarding workflows.
Step 6: Manager Module
  • Team Dashboard → View team members and performance.
  • Approve Leave → Approve/reject leave requests.
  • Reports → Attendance and performance reports.
Step 7: Employee Module
  • Profile → View/update personal details.
  • Attendance → Mark attendance.
  • Leave Application → Submit leave requests.
  • Salary Slip → View/download salary slips.
  • Offer Letter → View recruitment documents.
Step 8: Payroll & Reports
  • Payroll Management → Salary calculation, deductions, bonuses.
  • Salary Slips → Generate and export slips.
  • Reports → Attendance, payroll, performance analytics.
Step 9: Deployment
  • Publish to IIS or Azure.
  • Configure connection strings for production.
  • Secure sensitive data with Azure Key Vault or environment variables.
Admin Module – Companies, Departments, Designations
Companies Page

Step 1: Model

public class Company
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int LocId { get; set; }
    public string Address { get; set; }

    public Location Location { get; set; }
    public ICollection<Department> Departments { get; set; }
}

Step 2: Controller
public class CompaniesController : Controller
{
    private readonly ApplicationDbContext _context;
    public CompaniesController(ApplicationDbContext context) => _context = context;

    public async Task<IActionResult> Index()
    {
        var companies = await _context.Companies.Include(c => c.Location).ToListAsync();
        return View(companies);
    }

    public IActionResult Create() => View();

    [HttpPost]
    public async Task<IActionResult> Create(Company company)
    {
        if (ModelState.IsValid)
        {
            _context.Add(company);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
        return View(company);
    }
}


Step 3: View
@model IEnumerable<Company>

<h2>Companies</h2>
<table class="table">
    <tr><th>Name</th><th>Location</th><th>Address</th></tr>
    @foreach (var c in Model)
    {
        <tr>
            <td>@c.Name</td>
            <td>@c.Location.Name</td>
            <td>@c.Address</td>
        </tr>
    }
</table>

Departments Page
Step 1: Model

public class Department
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int CompanyId { get; set; }

    public Company Company { get; set; }
}


Step 2: Controller
public class DepartmentsController : Controller
{
    private readonly ApplicationDbContext _context;
    public DepartmentsController(ApplicationDbContext context) => _context = context;

    public async Task<IActionResult> Index()
    {
        var departments = await _context.Departments.Include(d => d.Company).ToListAsync();
        return View(departments);
    }

    public IActionResult Create() => View();

    [HttpPost]
    public async Task<IActionResult> Create(Department department)
    {
        if (ModelState.IsValid)
        {
            _context.Add(department);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
        return View(department);
    }
}

Step 3: View

@model IEnumerable<Department>

<h2>Departments</h2>
<table class="table">
    <tr><th>Name</th><th>Company</th></tr>
    @foreach (var d in Model)
    {
        <tr>
            <td>@d.Name</td>
            <td>@d.Company.Name</td>
        </tr>
    }
</table>

Designations Page
Step 1: Model

public class Designation
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int CompanyId { get; set; }

    public Company Company { get; set; }
}


Step 2: Controller
public class DesignationsController : Controller
{
    private readonly ApplicationDbContext _context;
    public DesignationsController(ApplicationDbContext context) => _context = context;

    public async Task<IActionResult> Index()
    {
        var designations = await _context.Designations.Include(d => d.Company).ToListAsync();
        return View(designations);
    }

    public IActionResult Create() => View();

    [HttpPost]
    public async Task<IActionResult> Create(Designation designation)
    {
        if (ModelState.IsValid)
        {
            _context.Add(designation);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
        return View(designation);
    }
}


Step 3: View
@model IEnumerable<Designation>

<h2>Designations</h2>
<table class="table">
    <tr><th>Name</th><th>Company</th></tr>
    @foreach (var d in Model)
    {
        <tr>
            <td>@d.Name</td>
            <td>@d.Company.Name</td>
        </tr>
    }
</table>


Employee Model
Define the employee entity with relationships to company, department, and designation:
public class Employee
{
    public int Id { get; set; }
    public string FullName { get; set; }
    public string Email { get; set; }
    public string Phone { get; set; }

    public int CompanyId { get; set; }
    public Company Company { get; set; }

    public int DepartmentId { get; set; }
    public Department Department { get; set; }

    public int DesignationId { get; set; }
    public Designation Designation { get; set; }

    public DateTime JoiningDate { get; set; }
}


Employee Controller
Create an MVC controller to handle CRUD operations:
public class EmployeesController : Controller
{
    private readonly ApplicationDbContext _context;
    public EmployeesController(ApplicationDbContext context) => _context = context;

    // List all employees
    public async Task<IActionResult> Index()
    {
        var employees = await _context.Employees
            .Include(e => e.Company)
            .Include(e => e.Department)
            .Include(e => e.Designation)
            .ToListAsync();
        return View(employees);
    }

    // Create employee
    public IActionResult Create()
    {
        ViewBag.Companies = new SelectList(_context.Companies, "Id", "Name");
        ViewBag.Departments = new SelectList(_context.Departments, "Id", "Name");
        ViewBag.Designations = new SelectList(_context.Designations, "Id", "Name");
        return View();
    }

    [HttpPost]
    public async Task<IActionResult> Create(Employee employee)
    {
        if (ModelState.IsValid)
        {
            _context.Add(employee);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
        return View(employee);
    }

    // Edit employee
    public async Task<IActionResult> Edit(int id)
    {
        var employee = await _context.Employees.FindAsync(id);
        if (employee == null) return NotFound();

        ViewBag.Companies = new SelectList(_context.Companies, "Id", "Name", employee.CompanyId);
        ViewBag.Departments = new SelectList(_context.Departments, "Id", "Name", employee.DepartmentId);
        ViewBag.Designations = new SelectList(_context.Designations, "Id", "Name", employee.DesignationId);

        return View(employee);
    }

    [HttpPost]
    public async Task<IActionResult> Edit(Employee employee)
    {
        if (ModelState.IsValid)
        {
            _context.Update(employee);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
        return View(employee);
    }

    // Delete employee
    public async Task<IActionResult> Delete(int id)
    {
        var employee = await _context.Employees.FindAsync(id);
        if (employee == null) return NotFound();

        _context.Employees.Remove(employee);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
}

Employee Views
Index.cshtml
@model IEnumerable<Employee>

<h2>Employees</h2>
<a asp-action="Create" class="btn btn-primary">Add Employee</a>

<table class="table">
    <tr>
        <th>Name</th><th>Email</th><th>Phone</th>
        <th>Company</th><th>Department</th><th>Designation</th><th>Joining Date</th><th>Actions</th>
    </tr>
    @foreach (var e in Model)
    {
        <tr>
            <td>@e.FullName</td>
            <td>@e.Email</td>
            <td>@e.Phone</td>
            <td>@e.Company.Name</td>
            <td>@e.Department.Name</td>
            <td>@e.Designation.Name</td>
            <td>@e.JoiningDate.ToShortDateString()</td>
            <td>
                <a asp-action="Edit" asp-route-id="@e.Id">Edit</a> |
                <a asp-action="Delete" asp-route-id="@e.Id">Delete</a>
            </td>
        </tr>
    }
</table>


Create.cshtml
@model Employee

<h2>Add Employee</h2>
<form asp-action="Create">
    <div class="form-group">
        <label>Name</label>
        <input asp-for="FullName" class="form-control" />
    </div>
    <div class="form-group">
        <label>Email</label>
        <input asp-for="Email" class="form-control" />
    </div>
    <div class="form-group">
        <label>Phone</label>
        <input asp-for="Phone" class="form-control" />
    </div>
    <div class="form-group">
        <label>Company</label>
        <select asp-for="CompanyId" asp-items="ViewBag.Companies" class="form-control"></select>
    </div>
    <div class="form-group">
        <label>Department</label>
        <select asp-for="DepartmentId" asp-items="ViewBag.Departments" class="form-control"></select>
    </div>
    <div class="form-group">
        <label>Designation</label>
        <select asp-for="DesignationId" asp-items="ViewBag.Designations" class="form-control"></select>
    </div>
    <div class="form-group">
        <label>Joining Date</label>
        <input asp-for="JoiningDate" type="date" class="form-control" />
    </div>
    <button type="submit" class="btn btn-success">Save</button>
</form>




ASP.NET MVC Hosting - HostForLIFE.eu :: Kendo Grid in jQuery with All Relevant ASP.NET MVC Properties

clock May 29, 2026 08:32 by author Peter

When working with large data in web applications, displaying data in a simple HTML table becomes difficult.


We need features like:

  • Paging
  • Sorting
  • Filtering
  • Endless scrolling
  • Searching

To solve this problem, developers use Kendo UI Grid.

Kendo Grid is one of the most popular UI components used in ASP.NET MVC and jQuery applications.

In this article, you will learn:

  • What Kendo Grid is
  • Why we use it
  • Important grid properties
  • Endless scrolling
  • Fetching 50-50 records
  • Real examples with explanation

What is Kendo Grid?
Kendo Grid is a powerful table component provided by Progress Telerik.

It helps display data with advanced features using less code.

Why Use Kendo Grid?

  • Professional UI
  • Easy data handling
  • Built-in paging & filtering
  • Fast development

Step 1: Add Kendo UI Files
<link href="https://kendo.cdn.telerik.com/2024.1.130/styles/kendo.default-v2.min.css" rel="stylesheet" />

<script src="https://kendo.cdn.telerik.com/2024.1.130/js/kendo.all.min.js"></script>


Step 2: Create HTML Div
<div id="grid"></div>

Step 3: Create Grid
$("#grid").kendoGrid({
    dataSource: {
        transport: {
            read: {
                url: "/Home/GetStudents",
                dataType: "json"
            }
        },
        pageSize: 50
    },

    height: 550,

    pageable: true,

    sortable: true,

    filterable: true,

    scrollable: true,

    columns: [
        { field: "StudentId", title: "ID", width: 100 },
        { field: "StudentName", title: "Name" },
        { field: "City", title: "City" }
    ]
});


Output
Grid features:

  • Paging
  • Sorting
  • Filtering
  • Scrollable grid

Important Kendo Grid Properties Explained
pageable
pageable: true
Enables pagination

sortable
sortable: true
Allows column sorting


filterable
filterable: true
Adds filter option

scrollable
scrollable: true
Enables scrolling

groupable
groupable: true
Group data by column

selectable
selectable: true
Select row

resizable
resizable: true
Resize columns

reorderable
reorderable: true
Change column order

editable
editable: true

Enable editing
toolbar
toolbar: ["create"]
Add toolbar buttons

Endless Scrolling in Kendo Grid
What is Endless Scrolling?

Normally grid uses pagination.

But endless scrolling automatically loads more data while scrolling.

This improves user experience.
Example
scrollable: {
    endless: true
}

Full Example with Endless Scrolling
$("#grid").kendoGrid({

    dataSource: {
        transport: {
            read: {
                url: "/Home/GetStudents",
                dataType: "json"
            }
        },

        pageSize: 50,

        serverPaging: true
    },

    height: 500,

    scrollable: {
        endless: true
    },

    sortable: true,

    filterable: true,

    columns: [
        { field: "StudentId", title: "ID" },
        { field: "StudentName", title: "Name" },
        { field: "City", title: "City" }
    ]
});

What Does pageSize: 50 Mean?
pageSize: 50

Grid fetches 50 records at one time.

When user scrolls:

  • Next 50 records load automatically
  • Then next 50 records load

This improves:

  • Performance
  • Speed
  • Memory usage

Server Side Data Fetch Example
Controller
public JsonResult GetStudents(int page, int pageSize)
{
    List<Student> list = new List<Student>();

    for (int i = 1; i <= 500; i++)
    {
        list.Add(new Student
        {
            StudentId = i,
            StudentName = "Student " + i,
            City = "London"
        });
    }

    var data = list.Skip((page - 1) * pageSize).Take(pageSize);

    return Json(data, JsonRequestBehavior.AllowGet);
}


Explanation
Skip((page - 1) * pageSize)

Skips previous records
Take(pageSize)
Fetches only 50 records

Why Use 50-50 Data Fetching?

If database has:

100000 records

Loading all data together makes application slow.

Using:
pageSize: 50
Only 50 records load at a time.

Advantages of Endless Scrolling

  • Faster loading
  • Better performance
  • Smooth user experience
  • Less memory usage

Complete Advanced Grid Example
$("#grid").kendoGrid({

    dataSource: {
        transport: {
            read: {
                url: "/Home/GetStudents",
                dataType: "json"
            }
        },

        pageSize: 50,

        serverPaging: true,
        serverSorting: true,
        serverFiltering: true
    },

    height: 550,

    pageable: true,

    sortable: true,

    filterable: true,

    groupable: true,

    reorderable: true,

    resizable: true,

    selectable: "row",

    scrollable: {
        endless: true
    },

    toolbar: ["search"],

    columns: [
        { field: "StudentId", title: "ID", width: 100 },
        { field: "StudentName", title: "Student Name" },
        { field: "City", title: "City" }
    ]
});



ASP.NET MVC Hosting - HostForLIFE.eu :: Why MVC Is Superior to Web Forms?

clock May 20, 2026 09:01 by author Peter

The Reasons for MVC?
In the field of software development, MVC is a new standard design pattern. It's simple to utilize ASP.NET MVC.Google offers dozens of resources to help us learn how to program and configure the code.However, it is always preferable to begin with Why rather than How.

ASP.NET Web Forms cannot be replaced by ASP.NET MVC.Microsoft offers a different method for creating an application.

ASP.NET Web Form Problems:

  • Complexity:HTML and ASP.NET mark up code are used in a Single Page that's why code become very complex.
  • Tightly Coupled-Aspx page and cs page(code behind file) are tightly coupled.so that we can not work separately.
  • Unwanted Html and Java Script-when we drag and drop the controls then unwanted html and java script is automatically inserted in our code that's why page become heavier and it takes time to load on browser.
  • View state-One of the main problems with ASP.NET web forms is the viewstate mechanism, which takes a lot of bandwidth because it serializes all the form inputs and sends it on post commands.
  • Response Time -for any single events it follows the complete Page Life cycle Events life cycle that's why response time of any ASP.NET application is become more than the MVC application.

Benefits of MVC
Three are several benefits of using MVC are given below.

  • Separation of Concerns -Separation of Concern is one of the core advantages of ASP.NET MVC . The MVC framework provides a clean separation of the UI , Business Logic , Model or Data. On the other hand we can say it provides Sepration of Program logic from the User Interface.
  • More Control-The ASP.NET MVC framework provides more control over the HTML , JavaScript and CSS than the traditional Web Forms.
  • Testability-ASP.NET MVC framework provides better testability of the Web Application and good support for the test driven development too.
  • Lightweight-ASP.NET MVC framework doesn’t use View State and thus reduces the bandwidth of the requests to an extent.
  • Full features of ASP.NET-One of the key advantages of using ASP.NET MVC is that it is built on top of ASP.NET framework and hence most of the features of the ASP.NET like membership providers , roles etc can still be used.


ASP.NET MVC Hosting - HostForLIFE.eu :: How to Post a Collection?

clock May 12, 2026 09:13 by author Peter

Using an example application, I will explain how to submit a collection in ASP.Net MVC 3. The fundamental principle of posting (carrying HTML field values from view to controller) is to match receiving parameters in the Controller's action method with the name field of the displayed HTML control.

 

Let's say I have a field in my Razor view called @Html.TextBox ("myName", "Peter") inside a form tag. When I submit the form, I can get the value "Peter" from the variable "myName" in the Controller's action function as follows:
    [HttpPost]  
    public ActionResult ReceveMyName(string myName)  
    {  
    }  


So in the following section I will describe how to post a collection from the view to the controller by a sample application using MVC razor view.

In the sample application we have the screen, where we can "Add" the status/comments in the text area. Once we "Add" the status, the same will be reflected in the down portion.

We have a "Save" button at the down that will save the entire collection to the database. Here the content we are updating in text area is a "Tweet" model.

Tweet Model
    public class Tweet  
    {  
        public Tweet()  
        {  
            Date = DateTime.UtcNow;  
        }  
        private DateTime date;  
        public int Id { get; set; }   
        public string UserName { get; set; }  
        public string Text { get; set; }        
        public DateTime Date  
        {  
            get { return date.ToLocalTime(); }  
            set { date = value; }  
        }  
    } 

Once we add the comments we need to post the entire "Collection of Tweets" and "Tweet" to the controller action. In other words, textarea refers to a single Tweet by the user and the down shows the list of tweets provided by all the followers and the user.

View Model
So our view model will be as in the following:
    public class TwitterViewModel  
    {  
        public Tweet Tweet { get; set; }  
        public IList<Tweet> Tweets { get; set; }  
    } 


Views
Our main view is "Tweets.cshtml" as in the following and which will render another partial view "_Alltweets.cshtml" by passing the model.

Tweets.cshtml
    @model MongoTwitter.ViewModels.TwitterViewModel  
    @{  
        ViewBag.Title = "Twitter";  
    }  
    <hgroup class="title">  
    <h2>What's happening</h2>  
    </hgroup>  
    <div style="width: 600px; border: 1px solid silver">  
        @using (Ajax.BeginForm("AddTweet", "Home", new AjaxOptions { UpdateTargetId = "AllTweets" }))  
        {   
            <div style="width: 600px; border-width: 1px">  
                @Html.TextAreaFor(md => md.Tweet.Text)  
                <input type="submit" value="Add" style="width: 70px; font-size: 12px" />  
            </div>  
            <div id="AllTweets">  
                @Html.Partial("_AllTweets", Model)  
            </div>  
        }  
    </div>


_AllTweets.cshtml

    @model MongoTwitter.ViewModels.TwitterViewModel  
    @using (Html.BeginForm("SaveTweet", "Home"))  
    {  
        <div style="height: 300px; width: 600px; overflow-y: auto">  
            <table border="1">  
                @if (Model != null && Model.Tweets != null)  
                {  
                    for (int i = 0; i < Model.Tweets.Count; i++)  
                    {  
                     
                    <tr style="vertical-align: top">  
                        <td style="font-size: 12px; padding-left: 2px">  
                            @Html.DisplayFor(modelItem => Model.Tweets[i].Date) -  
                            @Html.DisplayFor(modelItem => Model.Tweets[i].UserName) :  
                        </td>  
                        <td>  
                            @Html.Raw(Model.Tweets[i].Text.Replace("\r\n", "<br />"))  
                        </td>  
                    </tr>  
                    @Html.HiddenFor(modelItem => Model.Tweets[i].Id)   
                    @Html.HiddenFor(modelItem => Model.Tweets[i].Date)   
                    @Html.HiddenFor(modelItem => Model.Tweets[i].Text)   
                    @Html.HiddenFor(modelItem => Model.Tweets[i].UserName)   
                    }  
                }  
            </table>  
        </div>  
        <input type="submit" value="Save" style="float: right; width: 70px; font-size: 12px" />  
    }


The main things to note about "AllTweets.cshtml" is that, we have used a for loop to loop through all the items in the Tweets Collection for (int i = 0; i < Model.Tweets.Count; i++). Here by using developer tools if we inspect the rendered HTML, we will see that the name field of the entire collection matches what needs to be posted for that collection, like Tweets[1].Id, Tweets[2].Id etc. 

HTML rendered using For Loop
If we use a foreach loop instead of a for loop then the collection won't post because if we use a foreach loop then the name field for each item in the rendered HTML.

HTML rendered using foreach loop.

Another important thing to note in "_AllTweets.cshtml" is that we have used @Html.HiddenFor() for the fields like id, Date and Text, that are displayed using @Html.DisplayFor() just above. Since DisplayFor() won't post a value to the controller we use @Html.HiddenFor(). By clicking the "Add" button in "_AllTweets.cshtml" the following action will be called. Since the entire collection is posted back in "viewModel.Tweets", we will add the new Tweet into that collection and return the view with updated Model.

    /// <summary>  
    /// Add posted tweet from TweetViewModel to tweet collection  
    /// </summary>  
    /// <param name="viewModel"></param>  
    /// <returns></returns>  
    [HttpPost]  
    public ActionResult AddTweet(TwitterViewModel viewModel)  
    {  
        try  
        {  
            viewModel.Tweets.Add(viewModel.Tweet);  
            return PartialView("_AllTweets", viewModel);  
        }  
        catch  
        {  
            return View();  
        }  
    } 

In image above we can see the SaveTweet() post action, where "TwitterViewModel" is posted back, that has the value for all Tweets collections. 



ASP.NET MVC Hosting - HostForLIFE.eu :: Monitor User Login and Logout Times in ASP.NET MVC

clock April 13, 2026 09:14 by author Peter

User activity tracking is crucial for security, auditing, and analytics in real-world web applications. Keeping track of a user's login and logout times is one of the most popular needs. Using an audit log table, we will create a straightforward and efficient ASP.NET MVC system in this post to monitor user login and logout times.

Why Do We Need Audit Tracking?
Tracking login and logout activity helps in:

  • Monitoring user sessions
  • Maintaining security logs
  • Analyzing user behavior
  • Debugging issues related to authentication

Features Implemented

  • User login system
  • Session management
  • Login time recording
  • Logout time update
  • Audit log tracking

Database Design
We will use two tables: users and auditlogs.
CREATE TABLE users (
    Id INT IDENTITY PRIMARY KEY,
    Name NVARCHAR(100),
    Contact NVARCHAR(21),
    Email NVARCHAR(150),
    Password NVARCHAR(200)
);

CREATE TABLE auditlogs (
    AuditId INT PRIMARY KEY IDENTITY,
    UserId INT,
    Username NVARCHAR(100),
    LoginDate DATETIME,
    LogoutDate DATETIME NULL
);


Explanation

  • LoginDate stores the login timestamp
  • LogoutDate is initially NULL and updated during logout
  • Each login creates a new record in auditlogs

Step 1: Login Logic
When a user logs in successfully:

  • Validate credentials
  • Store session values
  • Insert login time into audit table


loginc
public void InsertLogin(int userId, string username)
{
    string query = @"INSERT INTO auditlogs (UserId, Username, LoginDate)
                     VALUES (@UserId, @Username, GETDATE())";

    using (SqlConnection con = new SqlConnection(_connectionString))
    {
        SqlCommand cmd = new SqlCommand(query, con);
        cmd.Parameters.AddWithValue("@UserId", userId);
        cmd.Parameters.AddWithValue("@Username", username);

        con.Open();
        cmd.ExecuteNonQuery();
    }
}

Step 2: Logout Logic
When the user logs out:

  • Find the latest active session
  • Update logout time

logoutc
public void UpdateLogout(int userId)
{
    string query = @"UPDATE auditlogs
                     SET LogoutDate = GETDATE()
                     WHERE UserId = @UserId AND LogoutDate IS NULL";

    using (SqlConnection con = new SqlConnection(_connectionString))
    {
        SqlCommand cmd = new SqlCommand(query, con);
        cmd.Parameters.AddWithValue("@UserId", userId);

        con.Open();
        cmd.ExecuteNonQuery();
    }
}


Important Note
We use LogoutDate IS NULL to ensure only the active session is updated.

Step 3: Controller Implementation

Login Action
[HttpPost]
public IActionResult Login(string email, string password)
{
    var user = _userService.GetUser(email, password);

    if (user != null)
    {
        HttpContext.Session.SetInt32("UserId", user.Id);
        HttpContext.Session.SetString("Username", user.Name);

        _auditService.InsertLogin(user.Id, user.Name);

        return RedirectToAction("Index", "Home");
    }

    ViewBag.Error = "Invalid Credentials";
    return View();
}

Logout Action
public IActionResult Logout()
{
    int? userId = HttpContext.Session.GetInt32("UserId");

    if (userId != null)
    {
        _auditService.UpdateLogout(userId.Value);
    }

    HttpContext.Session.Clear();
    return RedirectToAction("Login");
}


Output

After login and logout operations, the auditlogs table will store data like:

Best Practices

  • Use a service layer instead of writing SQL in controllers
  • Always validate user input
  • Avoid storing plain text passwords (use hashing)
  • Handle session expiration properly

Common Mistakes

  • Not updating logout time
  • Inserting duplicate login records unnecessarily
  • Mixing business logic inside controllers
  • Ignoring null session cases

Conclusion
In this article, we implemented a simple audit tracking system in ASP.NET MVC to record user login and logout time. This approach can be extended further to include additional tracking details such as IP address, device information, and user activity logs.



ASP.NET MVC Hosting - HostForLIFE.eu :: How to Transfer Data in ASP.NET MVC Between Controller and View?

clock March 16, 2026 07:33 by author Peter

Communication between the Controller and View is crucial in ASP.NET MVC.

  • Data is sent to the View by the Controller once it has processed requests.
  • User input is gathered by the View and returned to the Controller.

CRUD (Create, Read, Update, Delete) systems and other dynamic web applications are made possible by this two-way communication.

This essay will teach us:

  • How to pass Controller → View data
  • How to send data from View to Controller
  • Various methods
  • A basic example of CRUD

Everything is explained in simple beginner-friendly steps.

MVC Architecture Overview
MVC stands for:

ComponentResponsibility
Model Handles data and business logic
View Displays UI
Controller Handles user requests

Flow example:
Ways to Transfer Data from Controller to View: User → Controller → Model → Controller → View → User

There are four common methods.

MethodType
ViewBag Dynamic object
ViewData Dictionary object
TempData Temporary storage
Model Strongly typed object

1 Passing Data Using ViewBag

ViewBag is a dynamic property used to pass small data.
Controller
public ActionResult Index()
{
    ViewBag.Name = "Scott";
    ViewBag.City = "London";

    return View();
}

View
<h2>Name: @ViewBag.Name</h2>
<h2>City: @ViewBag.City</h2>


What is this?
Output
Name: Scott 
City: London

When to Use?

  • Small data
  • Simple messages

2 Passing Data Using ViewData
ViewData works like a dictionary.
Controller
public ActionResult Index()
{
    ViewData["Course"] = "ASP.NET MVC";
    return View();
}


View
<h2>@ViewData["Course"]</h2>

What is this?
3 Passing Data Using TempData

TempData stores data until the next request.

Controller

public ActionResult Index()
{
    TempData["Message"] = "Record Saved Successfully";
    return RedirectToAction("Display");
}

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


View
<h2>@TempData["Message"]</h2>

What is this?
4 Passing Data Using Model (Best Method)
This is the most recommended approach.

Step 1 Create Model

public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}

Step 2 Controller
public ActionResult Details()
{
    Student s = new Student()
    {
        Id = 1,
        Name = "Scott",
        Age = 22
    };

    return View(s);
}


Step 3 View
@model Student

<h2>ID: @Model.Id</h2>
<h2>Name: @Model.Name</h2>
<h2>Age: @Model.Age</h2>


Passing Data From View to Controller
Now let’s see how user input goes from View → Controller.
This is done using HTML forms.

Simple CRUD Example

We will build a simple Student CRUD system.

Step 1 Model
public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}

Step 2 Controller
public class StudentController : Controller
{
    static List<Student> students = new List<Student>();

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

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

    [HttpPost]
    public ActionResult Create(Student s)
    {
        students.Add(s);
        return RedirectToAction("Index");
    }
}

Step 3 Create View
@model Student

@using (Html.BeginForm())
{
    <label>Name</label>
    @Html.TextBoxFor(m => m.Name)

    <br/>

    <label>Age</label>
    @Html.TextBoxFor(m => m.Age)

    <br/>

    <input type="submit" value="Save"/>
}


Here the form sends data to the controller.

Step 4 Display Data
View

@model List<Student>

<table border="1">
<tr>
    <th>ID</th>
    <th>Name</th>
    <th>Age</th>
</tr>

@foreach(var item in Model)
{
<tr>
    <td>@item.Id</td>
    <td>@item.Name</td>
    <td>@item.Age</td>
</tr>
}
</table>

Flow of Data in CRUD
User enters data in View ↓ Form submits to Controller ↓ Controller receives Model ↓ Data saved ↓ Controller sends updated data to View ↓ View displays result

Important Concepts
Model Binding

Model binding automatically converts form values into model objects.

Example:
Name → Student.Name
Age → Student.Age

MVC automatically maps them.

Best Practice for Beginners

Always prefer Model-based data passing instead of ViewBag or ViewData.

Example:
Good
return View(student);


Not recommended
ViewBag.Name = "Peter";

Quick Comparison

MethodStrongly TypedUsage
ViewBag No Small data
ViewData No Simple data
TempData No Between requests
Model Yes Best for real applications

Conclusion

Passing data between Controller and View is one of the most important concepts in ASP.NET MVC development.
Developers can use:

 

  • ViewBag

 

  • ViewData

 

  • TempData

 

  • Models

 

However, for real-world applications and CRUD operations, the Model approach is the most powerful and recommended method.



ASP.NET MVC Hosting - HostForLIFE.eu :: ASP.NET MVC Model Binding

clock March 10, 2026 07:38 by author Peter

Developers frequently have to transfer data from the View to the Controller when creating web apps with ASP.NET MVC. For instance:

  • Filling out a login form
  • Creating a new user account
  • Form data storage in a database

Manually managing this data might be challenging. Fortunately, Model Binding is a potent feature offered by ASP.NET MVC. Form values, query strings, and route data are automatically mapped to C# objects by Model Binding.

In this article, we will learn:

  • What Model Binding is
  • Why it is useful
  • How it works in ASP.NET MVC
  • Simple examples for beginners

Everything is explained in easy words with step-by-step examples.

What is Model Binding?
Model Binding is a process where ASP.NET MVC automatically maps incoming request data to action method parameters.

This means data from:

  • Form fields
  • Query strings
  • Route values

can automatically be converted into C# objects or variables.

Simple Example

If a form has fields:
Name = Peter
Email = [email protected]


Model Binding automatically converts this data into a C# object.

Why Model Binding is Important

Model Binding makes development easier.

Benefits include:

  • Less manual coding
  • Automatic data mapping
  • Cleaner controller code
  • Faster development

Without model binding, developers would need to manually read values from Request.Form.

Step 1: Create a Model

First create a model class.

User.cs
public class User
{
    public string Name { get; set; }

    public string Email { get; set; }

    public string Password { get; set; }
}


This class represents a user object that will receive form data.

Step 2: Create Controller

Create a controller named UserController.
public class UserController : Controller
{
    public ActionResult Register()
    {
        return View();
    }
}


This method will display the registration form.

Step 3: Create View
Register.cshtml
<h2>User Registration</h2>

<form method="post" action="/User/Register">


Name:
<input type="text" name="Name" />

Email:
<input type="text" name="Email" />


Password:
<input type="password" name="Password" />
<input type="submit" value="Register" />

</form>


The input field names match the model properties. This is important because Model Binding uses these names to map data.

Step 4: Receive Data Using Model Binding

Now update the controller.
[HttpPost]
public ActionResult Register(User user)
{
    ViewBag.Message = "User Registered Successfully: " + user.Name;

    return View();
}


ASP.NET MVC automatically:

  • Reads form values
  • Creates a User object
  • Fills properties with form data

This process is called Model Binding.

Output
If a user submits the form:
Name = Peter
Email = [email protected]
Password = 12345


The controller receives:
user.Name = Peter
user.Email = [email protected]
user.Password = 12345


And displays:
User Registered Successfully: Peter

Types of Model Binding
ASP.NET MVC supports different types of model binding.

1 Simple Model Binding

Used for simple data types.

Example:
public ActionResult Index(string name)
{
}


2 Complex Model Binding
Used for objects.

Example:
public ActionResult Register(User user)
{
}


3 Collection Model Binding
Used for lists or arrays.

Example:
public ActionResult Save(List<User> users)
{
}


Where Model Binding Gets Data From
Model Binding can read data from different sources.

SourceExample
Form Data HTML forms
Query String URL parameters
Route Data MVC routing
Cookies Browser cookies

Example Using Query String

URL:
/User/Index?name=Peter

Controller:
public ActionResult Index(string name)
{
    ViewBag.Name = name;
    return View();
}


Output:
Welcome Peter

Common Mistakes Beginners Make
Beginners sometimes face issues because:

  • Input names do not match model properties
  • Model classes are not created properly
  • Incorrect HTTP method is used

Always make sure input field names match model properties.

Advantages of Model Binding

Model Binding makes development easier because:

 

  • No need to manually extract request values
  • Clean controller methods
  • Works with simple and complex data types
  • Automatically maps request data to objects

Conclusion
Model Binding is one of the most powerful features in ASP.NET MVC. It automatically converts incoming request data into C# objects or parameters, reducing the amount of manual coding required. By understanding how Model Binding works, developers can create cleaner, faster, and more maintainable MVC applications.



About HostForLIFE.eu

HostForLIFE.eu is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.

We have offered the latest Windows 2016 Hosting, ASP.NET Core 2.2.1 Hosting, ASP.NET MVC 6 Hosting and SQL 2017 Hosting.


Tag cloud

Sign in