GitHub - whyrupesh/secureProductInventoryService: this is full stack project using dotnet and angular frameworks.
this is full stack project using dotnet and angular frameworks. - whyrupesh/secureProductInventoryService
GitHub - whyrupesh/secureProductInventoryService: this is full stack project using dotnet and angular frameworks.
this is full stack project using dotnet and angular frameworks. - whyrupesh/secureProductInventoryService
ASP.NETCoreAPI ├──Controllers ├──Services ├──Repositories ├──EFCore(DbContext) ├──JWTAuthentication └──Role-basedAuthorization(optional)
dotnet new webapi -n backend cd backend
dotnet add package Microsoft.EntityFrameworkCore.Sqlite dotnet add package Microsoft.EntityFrameworkCore.Tools dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer dotnet add package BCrypt.Net-Next
Since i am on Mac that’s why I here used SQLite. ( for sql server, i can haved used docker, but it would make our project more complex).
Package | Purpose |
EFCore.Sqlite | SQLite database provider |
EFCore.Tools | Migrations & database update |
JwtBearer | JWT authentication |
BCrypt.Net-Next | Secure password hashing |
using backend.Services; using Microsoft.IdentityModel.Tokens; using backend.Data; using backend.DTOs; using backend.Models; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; namespace backend.Services; public class AuthService : IAuthService { private readonly AppDbContext _context; private readonly IConfiguration _config; public AuthService(AppDbContext context, IConfiguration config) { _context = context; _config = config; } public string Register(RegisterDto dto) { var user = new User { Username = dto.Username, PasswordHash = BCrypt.Net.BCrypt.HashPassword(dto.Password) }; _context.Users.Add(user); _context.SaveChanges(); return GenerateToken(user); } public string Login(LoginDto dto) { var user = _context.Users.SingleOrDefault(u => u.Username == dto.Username); if (user == null || !BCrypt.Net.BCrypt.Verify(dto.Password, user.PasswordHash)) throw new Exception("Invalid credentials"); return GenerateToken(user); } private string GenerateToken(User user) { var claims = new[] { new Claim(ClaimTypes.Name, user.Username), new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()) }; var key = new SymmetricSecurityKey( Encoding.UTF8.GetBytes(_config["Jwt:Key"])); var token = new JwtSecurityToken( issuer: _config["Jwt:Issuer"], audience: _config["Jwt:Audience"], claims: claims, expires: DateTime.UtcNow.AddHours(2), signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256) ); return new JwtSecurityTokenHandler().WriteToken(token); } }
using backend.Data; using backend.DTOs; using backend.Models; namespace ProductInventoryAPI.Services; public class ProductService : IProductService { private readonly AppDbContext _context; public ProductService(AppDbContext context) { _context = context; } public IEnumerable<Product> GetAll() => _context.Products.ToList(); public Product GetById(int id) => _context.Products.FirstOrDefault(p => p.Id == id); public Product Create(ProductDto dto) { var product = new Product { Name = dto.Name, Description = dto.Description, Price = (decimal)dto.Price, Quantity = dto.Quantity, Category = dto.Category, IsActive = dto.IsActive, CreatedDate = DateTime.UtcNow }; _context.Products.Add(product); _context.SaveChanges(); return product; } public void Update(int id, ProductDto dto) { var product = GetById(id); if (product == null) return; product.Name = dto.Name; product.Description = dto.Description; product.Price = (decimal)dto.Price; product.Quantity = dto.Quantity; product.Category = dto.Category; product.IsActive = dto.IsActive; _context.SaveChanges(); } public void Delete(int id) { var product = GetById(id); if (product == null) return; _context.Products.Remove(product); _context.SaveChanges(); } }
AuthService and ProductService and use them directly?”“Only Ram can deliver my packages.”
“Anyone who can deliver packages can work.”
public class ProductsController { private ProductService _service =new ProductService(); publicvoidGet() { _service.GetAll(); } }
ProductServicepublic class ProductsController { private readonly IProductService _service; public ProductsController(IProductService service) { _service = service; } }
public class FakeProductService :IProductService { public IEnumerable<Product>GetAll() =>new List<Product> {new Product { Name ="Test" } }; }
Reason | Benefit |
Loose coupling | Components independent |
Easy testing | Mock/Fake services |
Easy replacement | Change logic without breaking |
Clean architecture | Professional code |
DI means you do NOT create objects yourself. Someone else gives them to you.
public classAuthController { private AuthService _service =new AuthService(); public void Login() { } }
public classAuthController { private readonly IAuthService _service; public AuthController(IAuthService service) { _service = service; } }
AuthService?builder.Services.AddScoped<IAuthService, AuthService>();
“Whenever someone asks for IAuthService, give them AuthService.”
Controller“I don’t care HOW work is done.Just give me someone who can do it.”
Interface“Defines what can be done.”
Service“Implements how it is done.”
DI“Connects everything together.”
dotnet tool install --global dotnet-ef dotnet ef migrations add InitialCreate dotnet ef database update

using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using backend.DTOs; using backend.Services; namespace backend.Controllers; [Authorize] [ApiController] [Route("api/products")] public class ProductsController : ControllerBase { private readonly IProductService _service; public ProductsController(IProductService service) { _service = service; } [HttpGet] public IActionResult GetAll() => Ok(_service.GetAll()); [HttpGet("{id}")] public IActionResult Get(int id) => Ok(_service.GetById(id)); [HttpPost] public IActionResult Create(ProductDto dto) => Ok(_service.Create(dto)); [HttpPut("{id}")] public IActionResult Update(int id, ProductDto dto) { _service.Update(id, dto); return NoContent(); } [HttpDelete("{id}")] public IActionResult Delete(int id) { _service.Delete(id); return NoContent(); } }
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; using backend.Data; using backend.Services; using System.Text; using backend.Services; var builder = WebApplication.CreateBuilder(args); // SQLite builder.Services.AddDbContext<AppDbContext>(options => options.UseSqlite("Data Source=inventory.db")); // Services builder.Services.AddScoped<IAuthService, AuthService>(); builder.Services.AddScoped<IProductService, ProductService>(); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); // JWT builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = builder.Configuration["Jwt:Issuer"], ValidAudience = builder.Configuration["Jwt:Audience"], IssuerSigningKey = new SymmetricSecurityKey( Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])) }; }); builder.Services.AddAuthorization(); var app = builder.Build(); app.UseSwagger(); app.UseSwaggerUI(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();
dotnet build dotnet run