Introduction
In this article, we are going to create a product management web API with CRUD operations using .NET Core 6 and different forms with the help of React JS.
Prerequisites
- Visual Studio 2022
- VS Code
- SQL Server
- .NET Core SDK
- Node JS
Product Management Application
Step 1. Create a new Product Management .NET Core Web API.
Step 2. Install the following NuGet packages that we used for database migrations and connectivity with SQL Server.
![Packages]()
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 a SQL Server 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; }
protected readonly IConfiguration Configuration;
public AppDbContext(IConfiguration configuration)
{
Configuration = configuration;
}
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
}
}
}
Step 5. Add a product repository inside the repositories folder.
IProductRepository
using ProductManagementAPI.Entities;
namespace ProductManagementAPI.Repositories
{
public interface IProductRepository
{
void AddProduct(Product product);
void DeleteProduct(int id);
List<Product> GetAllProducts();
Product GetProductById(int id);
void UpdateProduct(Product product);
}
}
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 List<Product> GetAllProducts()
{
return _context.Products.ToList();
}
public Product GetProductById(int id)
{
return _context.Products.FirstOrDefault(p => p.Id == id);
}
public void AddProduct(Product product)
{
if (product == null)
{
throw new ArgumentNullException(nameof(product));
}
_context.Products.Add(product);
_context.SaveChanges();
}
public void UpdateProduct(Product product)
{
if (product == null)
{
throw new ArgumentNullException(nameof(product));
}
_context.Entry(product).State = EntityState.Modified;
_context.SaveChanges();
}
public void DeleteProduct(int id)
{
var product = _context.Products.Find(id);
if (product == null)
{
throw new ArgumentNullException(nameof(product));
}
_context.Products.Remove(product);
_context.SaveChanges();
}
}
}
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.Http;
using Microsoft.AspNetCore.Mvc;
using ProductManagementAPI.Entities;
using ProductManagementAPI.Repositories;
namespace ProductManagementAPI.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class ProductController : ControllerBase
{
private readonly IProductRepository _productRepository;
public ProductController(IProductRepository productRepository)
{
_productRepository = productRepository;
}
[HttpGet]
public IActionResult GetAllProducts()
{
var products = _productRepository.GetAllProducts();
return Ok(products);
}
[HttpGet("{id}")]
public IActionResult GetProductById(int id)
{
var product = _productRepository.GetProductById(id);
if (product == null)
{
return NotFound();
}
return Ok(product);
}
[HttpPost]
public IActionResult AddProduct([FromBody] Product product)
{
if (product == null)
{
return BadRequest();
}
_productRepository.AddProduct(product);
return CreatedAtAction(nameof(GetProductById), new { id = product.Id }, product);
}
[HttpPut("{id}")]
public IActionResult UpdateProduct(int id, [FromBody] Product product)
{
if (product == null || id != product.Id)
{
return BadRequest();
}
var existingProduct = _productRepository.GetProductById(id);
if (existingProduct == null)
{
return NotFound();
}
_productRepository.UpdateProduct(product);
return NoContent();
}
[HttpDelete("{id}")]
public IActionResult DeleteProduct(int id)
{
var existingProduct = _productRepository.GetProductById(id);
if (existingProduct == null)
{
return NotFound();
}
_productRepository.DeleteProduct(id);
return NoContent();
}
}
}
Step 7. Open the app settings file and add the database connection string.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"DefaultConnection": "Data Source=DESKTOP-8RL8JOG;Initial Catalog=ReactNetCoreCrudDb;User Id=sa;Password=database@1;"
}
}
Step 8. Register our services inside the service container and configure the middleware.
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());
});
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");
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Step 9. Execute the following entity framework database migration command to create a database and tables.
add-migration “v1”
update-database
Step 10. Finally, run the application and use Swagger UI to execute different API endpoints.
![Product Manager API]()
Create a client application using 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">
{products.map(product => (
<ProductListItem key={product.id} product={product} onDelete={() => handleDelete(product.id)} onEdit={handleEdit} />
))}
</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;
Product service.
// src/services/productService.js
import axios from 'axios';
const baseURL = 'https://localhost:7202/api/Product';
const productService = {
getAllProducts: async () => {
const response = await axios.get(baseURL);
return response.data;
},
addProduct: async (product) => {
const response = await axios.post(baseURL, product);
return response.data;
},
deleteProduct: async (id) => {
const response = await axios.delete(`${baseURL}/${id}`);
return response.data;
},
updateProduct: async (id, product) => {
const response = await axios.put(`${baseURL}/${id}`, product);
return response.data;
}
};
export default productService;
App component.
// src/App.js
import React, { useState } from 'react';
import ProductList from './components/ProductList/ProductList';
import ProductForm from './components/ProductForm/ProductForm';
function App() {
const [refresh, setRefresh] = useState(false);
const handleProductAdded = () => {
setRefresh(!refresh); // Toggle refresh state to trigger re-render
};
return (
<div>
<ProductList key={refresh} />
<ProductForm onProductAdded={handleProductAdded} />
</div>
);
}
export default App;
Step 5. Run the application using the following command and perform the different CRUD operations with the help of the same.
![Run the application]()
Github: https://github.com/Jaydeep-007/React_NETCore_CRUD
Conclusion
In this article, we created a product management backend application using .NET Core and SQL Server with different API endpoints that are required to perform CRUD operations. Later on, I created the front-end application using React JS and consumed the back-end application inside the same with the help of Axios.