Introduction
In this article, we gonna create a sample product application using the.NET Core Web API and React JS. Also, will containerize the same with the help of Azure Kubernetics Services.
Agenda
- Sample Product Application Backend (.NET Core Web API)
- Sample Product Application Frontend (React JS)
- Docker Files for Application
- Containerize the Application
Prerequisites
- Visual Studio
- Docker Runtime and AKS
- NPM
- .NET Core SDK
- React JS
Sample Product Application: Backend (.NET Core Web API)
Step 1. Create a new Product Management.NET Core Web API.
Step 2. First, install the following NuGet packages that we used for the in-memory database.

Step 3. Add the product class inside the entities folder.
namespace ProductManagementAPI.Entities
{
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
}
Step 4. Create an AppDbContext class inside the data folder with an in-memory connection and a DB set property.
using Microsoft.EntityFrameworkCore;
using ProductManagementAPI.Entities;
namespace ProductManagementAPI.Data
{
public class AppDbContext : DbContext
{
public DbSet<Product> Products { get; set; }
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// This check prevents configuring the DbContext if options are already provided
if (!optionsBuilder.IsConfigured)
{
// Configure the in-memory database here, if needed
optionsBuilder.UseInMemoryDatabase("InMemoryDb");
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Optionally configure entity mappings here
}
}
}
Step 5. Add a product repository inside the repositories folder.
IProductRepository
using ProductManagementAPI.Entities;
namespace ProductManagementAPI.Repositories
{
public interface IProductRepository
{
Task<List<Product>> GetAllProductsAsync();
Task<Product> GetProductByIdAsync(int id);
Task AddProductAsync(Product product);
Task UpdateProductAsync(Product product);
Task DeleteProductAsync(int id);
}
}
ProductRepository
using Microsoft.EntityFrameworkCore;
using ProductManagementAPI.Data;
using ProductManagementAPI.Entities;
namespace ProductManagementAPI.Repositories
{
public class ProductRepository : IProductRepository
{
private readonly AppDbContext _context;
public ProductRepository(AppDbContext context)
{
_context = context;
}
public async Task<List<Product>> GetAllProductsAsync()
{
return await _context.Products.ToListAsync();
}
public async Task<Product> GetProductByIdAsync(int id)
{
return await _context.Products
.AsNoTracking()
.FirstOrDefaultAsync(p => p.Id == id);
}
public async Task AddProductAsync(Product product)
{
if (product == null)
{
throw new ArgumentNullException(nameof(product));
}
_context.Products.Add(product);
await _context.SaveChangesAsync();
}
public async Task UpdateProductAsync(Product product)
{
if (product == null)
{
throw new ArgumentNullException(nameof(product));
}
_context.Entry(product).State = EntityState.Modified;
await _context.SaveChangesAsync();
}
public async Task DeleteProductAsync(int id)
{
var product = await _context.Products.FindAsync(id);
if (product == null)
{
throw new KeyNotFoundException("Product not found.");
}
_context.Products.Remove(product);
await _context.SaveChangesAsync();
}
}
}
Step 6. Create a new product controller with different action methods that we used to perform different operations using our front-end application after invoking the same.
using Microsoft.AspNetCore.Mvc;
using ProductManagementAPI.Entities;
using ProductManagementAPI.Repositories;
namespace ProductManagementAPI.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private readonly IProductRepository _repository;
public ProductsController(IProductRepository repository)
{
_repository = repository;
}
[HttpGet]
public async Task<IActionResult> GetAllProducts()
{
var products = await _repository.GetAllProductsAsync();
return Ok(products); // Returns only the list of products
}
[HttpGet("{id}")]
public async Task<IActionResult> GetProductById(int id)
{
var product = await _repository.GetProductByIdAsync(id);
if (product == null)
{
return NotFound();
}
return Ok(product); // Returns only the product data
}
[HttpPost]
public async Task<IActionResult> AddProduct([FromBody] Product product)
{
if (product == null)
{
return BadRequest();
}
await _repository.AddProductAsync(product);
return CreatedAtAction(nameof(GetProductById), new { id = product.Id }, product);
}
[HttpPut("{id}")]
public async Task<IActionResult> UpdateProduct(int id, [FromBody] Product product)
{
if (product == null || id != product.Id)
{
return BadRequest();
}
await _repository.UpdateProductAsync(product);
return NoContent();
}
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteProduct(int id)
{
await _repository.DeleteProductAsync(id);
return NoContent();
}
}
}
Step 7. Register our services inside the service container and configure the middleware.
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using ProductManagementAPI.Data;
using ProductManagementAPI.Repositories;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddScoped<IProductRepository, ProductRepository>();
builder.Services.AddDbContext<AppDbContext>();
builder.Services.AddCors(options =>
{
options.AddPolicy("CORSPolicy", builder => builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
});
// Configure in-memory database
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseInMemoryDatabase("InMemoryDb"));
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseCors("CORSPolicy");
app.UseSwagger();
app.UseSwaggerUI();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Step 8. Finally, run the application and use Swagger UI to execute different API endpoints.

Sample Product Application: Frontend (React JS)
Let’s create a client application using React JS and consume the above API endpoints within it.
Step 1. Create a new React JS application with the help of the following command.
npx create-react-app react-netcore-crud-app
Step 2. Navigate to your project directory.
cd react-netcore-crud-app
Step 3. Install Axios to consume and hit backend API and bootstrap for designing purposes.
npm install axios
npm install bootstrap
Step 4. Add the following components and services.
Product list component
// src/components/ProductList/ProductList.js
import React, { useState, useEffect } from 'react';
import ProductListItem from './ProductListItem';
import productService from '../../services/productService';
const ProductList = () => {
const [products, setProducts] = useState([]);
useEffect(() => {
fetchProducts();
}, []);
const fetchProducts = async () => {
try {
const productsData = await productService.getAllProducts();
setProducts(productsData);
} catch (error) {
console.error('Error fetching products:', error);
}
};
const handleDelete = async (id) => {
try {
await productService.deleteProduct(id);
fetchProducts(); // Refresh product list
} catch (error) {
console.error('Error deleting product:', error);
}
};
const handleEdit = () => {
fetchProducts(); // Refresh product list after editing
};
return (
<div className="container">
<h2 className="my-4">Product List</h2>
<ul className="list-group">
{Array.isArray(products) && products.length > 0 ? (
products.map(product => (
<ProductListItem
key={product.id}
product={product}
onDelete={() => handleDelete(product.id)}
onEdit={handleEdit}
/>
))
) : (
<p>No products available</p>
)}
</ul>
</div>
);
};
export default ProductList;
Product list item component
// src/components/ProductList/ProductListItem.js
import React, { useState } from 'react';
import productService from '../../services/productService';
const ProductListItem = ({ product, onDelete, onEdit }) => {
const [isEditing, setIsEditing] = useState(false);
const [editedName, setEditedName] = useState(product.name);
const [editedPrice, setEditedPrice] = useState(product.price);
const handleEdit = async () => {
setIsEditing(true);
};
const handleSave = async () => {
const editedProduct = { ...product, name: editedName, price: parseFloat(editedPrice) };
try {
await productService.updateProduct(product.id, editedProduct);
setIsEditing(false);
onEdit(); // Refresh product list
} catch (error) {
console.error('Error updating product:', error);
}
};
const handleCancel = () => {
setIsEditing(false);
// Reset edited values
setEditedName(product.name);
setEditedPrice(product.price);
};
return (
<li className="list-group-item">
{isEditing ? (
<div className="row">
<div className="col">
<input
type="text"
className="form-control"
value={editedName}
onChange={e => setEditedName(e.target.value)}
required
/>
</div>
<div className="col">
<input
type="number"
className="form-control"
value={editedPrice}
onChange={e => setEditedPrice(e.target.value)}
required
/>
</div>
<div className="col-auto">
<button className="btn btn-success me-2" onClick={handleSave}>Save</button>
<button className="btn btn-secondary" onClick={handleCancel}>Cancel</button>
</div>
</div>
) : (
<div className="d-flex justify-content-between align-items-center">
<span>{product.name} - ${product.price}</span>
<div>
<button className="btn btn-danger me-2" onClick={onDelete}>Delete</button>
<button className="btn btn-primary" onClick={handleEdit}>Edit</button>
</div>
</div>
)}
</li>
);
};
export default ProductListItem;
















Mohit KalaPosted Dec 24, 2024, 6:45 PM
Thanks for sharing in detailed article. its really helpful .