A simple and modular eCommerce web application built using ASP.NET Core MVC. This project demonstrates key concepts like layered architecture, Entity Framework Core, Identity, and Razor views, Desigen patterns (Repostry pattern,Unit of work, strategy pattern), tailored for learning and real-world application.
-
π Product browsing & details
-
π§Ύ Shopping cart
-
π€ User registration , login , Reset password , Forget password & Confirm Email (ASP.NET Core Identity)
-
π¦ Admin panel for managing products and categories
-
π Product search and filtering by (name | description)
-
π§© responsive design
-
π± Get products by category
-
β οΈ Error Pages (401 , 403 , 404 , 500 & general error page) -
π Optimized log data retrieval in admin view (350+ records) by adding a composite index on
timestampandid, reducing query time from ~26,907 ms to ~28 ms (β 970x faster) -
Dashboard for admin
-
Order history and checkout process
-
Locking Product row using Pessimistic Locking and using transction for roll back if product updated.
-
ASP.NET Core MVC (.NET 8)
-
C# (LINQ, Dependency Injection)
-
Dapper for reading data (Micro ORM)
-
SQL Server with Entity Framework Core (Code-First)
-
ASP.NET Core Identity
-
Bootstrap 5
-
Design Patterns (MVC + Repository Pattern + Unit of work + Strategy Pattern)
-
N-tiers architecture
-
In memory Caching
-
Hangfire (Background job)
-
Docker (Dokcer-Compose)
-
Serilog
eShop/
βββ src/
β βββ eShop.MVC => UI & Controller Layer (ASP.NET Core MVC)
β βββ eShop.Core => Entities, Utilities
β βββ eShop.DAL => Unit of Work & Repositories & Data Context & Migrations & Disk i/o
β βββ eShop.Business => Services & ViewModel & Attributes & Exceptions & Mapping
βββ test/
β βββ unit/
β βββ eShop.BLL.Tests => Unit Tests
-
SQL Server (LocalDB or any other)
-
Visual Studio / VS Code
bash
# 1. Clone the repository
git clone https://github.com/AbdullahHanfi/eShop.git
# 2. Navigate to the MVC project
cd eShop/eShop.MVC
# 3. Run the application
dotnet run
β The database will be created, and migrations will be applied automatically at startup.
Then go to https://localhost:7064 in your browser.
bash
# 1. Clone the repository
git clone https://github.com/AbdullahHanfi/eShop.git
# 2. Navigate to the root project directory
cd eShop
# 3. Build and run the application using Docker Compose
docker-compose up --build
β The database will be initialized automatically by the application on startup.
Then go to http://localhost:8080 in your browser.
-
Email:
superadmin@gmail.com -
Password:
superadmin@gmail.com
-
Email:
user@gmail.com -
Password:
user@gmail.com
β οΈ These credentials are for testing or demo purposes only. Make sure to update them before deploying to production.
Hereβs a simple example for InMemory Cache:
[HttpGet("categories")]
public async Task<IActionResult> GetCategories()
{
if (_cache.TryGetValue(CacheKeys.ProductsKey, out List<CategoryViewModel> cachedCategories))
{
return Ok(cachedCategories);
}
var model = await _unitOfWork.Categories.FindAllAsync(e => e.MainLayout);
if (model is null)
return Ok(new List<CategoryViewModel>());
var result = new List<CategoryViewModel>();
result = _mapper.Map<List<CategoryViewModel>>(model.ToList());
_cache.Set(CacheKeys.CategoriesKey, result, TimeSpan.FromMinutes(5));
return Ok(result);
}Hereβs a simple example for Dapper:
public TEntity GetById(Guid Id)
{
try
{
using (var _connection = new SqlConnection(_CN))
{
string tableName = GetTableName(typeof(TEntity));
string idName = GetKeyColumnName(typeof(TEntity));
string query = $"SELECT * FROM {tableName} where {idName} = @Id AND IsDeleted = 'false'";
return _connection.QueryFirstOrDefault<TEntity>(query, new { Id = Id });
}
}
catch (Exception ex) { }
return null;
}Hereβs a simple example for reading from EF metaData:
protected string GetKeyColumnName(Type entityType)
{
var entity = _context.Model.FindEntityType(entityType);
if (entity == null)
return string.Empty;
var key = entity.FindPrimaryKey();
if (key == null || key.Properties.Count == 0)
return string.Empty;
var keyProperty = key.Properties[0];
var tableName = entity.GetTableName();
var schema = entity.GetSchema();
return keyProperty.GetColumnName(StoreObjectIdentifier.Table(tableName, schema));
}Hereβs a simple example of modular service registration keeps the Program.cs clean and your layers loosely coupled :
public static class ServiceRegisterationBLL
{
public static void Add(this IServiceCollection services)
{
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.AddScoped<IEmailSender, EmailSender>();
services.AddScoped<IAccountServies, AccountServies>();
services.AddScoped<IImageServices, ImageServices>();
services.AddScoped<IMailTransport, MailTransport>();
services.AddScoped<IGuidProvider, GuidProvider>();
services.AddAutoMapper(typeof(AccountProfile));
services.AddAutoMapper(typeof(ProductProfile));
}
}
public class Program
{
public static void Main(string[] args)
{
ServiceRegisterationBLL.Add(builder.Services);
}
}-
Payment integration
-
Order history and checkout process (Done)
-
Email notifications for new products
-
Ability for super admin to manage admins
-
Unit testing for other component
-
Adding logging (Done)
Pull requests are welcome! For major changes, please open an issue first to discuss what youβd like to change.
.png)
.png)
.png)
.png)
.png)
.png)
.png)