
August 19, 2025 10:17 by
Peter
It can be challenging to manage packages in a.NET solution with numerous projects. You've probably seen issues like this if you've worked on big apps with dozens or even hundreds of projects.
- Projects utilizing various iterations of the same NuGet package are known as version mismatches.
- Manual labor: Each must be updated. csproj files one after the other.
- Build failures: CI/CD pipelines malfunctioning due to mismatched package versions.
To make this easier, Microsoft introduced Central Package Management (CPM) in .NET, starting with NuGet 6.0 and SDK-style projects.
What is Central Package Management?
Central Package Management lets you keep all NuGet package versions in one central file for your solution. Instead of writing the version number in every project file, you set it once in a file called Directory.Packages.props, and all projects use that version.
This makes upgrades easier, keeps versions consistent, and reduces maintenance work.
How It Works
Create a central file:
At the solution’s root, add a file named Directory.Packages.props.
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="RabbitMQ.Client" Version="7.1.2" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="9.0.3" />
</ItemGroup>
</Project>
Central Package Management
2. Reference packages in projects (without specifying versions):
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" />
<PackageReference Include="RabbitMQ.Client" />
</ItemGroup>
</Project>
Central Package Management
Note: The project file doesn’t include a version number. Instead, the version is defined in Directory.Packages.props.
3. Automatic adoption:
The .NET SDK automatically finds the Directory.Packages.props file in your solution folder and applies it to all projects.
Benefits of Central Package Management
- Consistency – Every project uses the same package version, avoiding conflicts.
- One place to update – Change the version in a single file instead of many.
- Fewer code conflicts – No version mismatches in .csproj files.
- Reliable builds – CI/CD pipelines run more smoothly.
- Simpler project files – .csproj files stay clean and easy to read.
Here’s a simpler example with different packages:
Suppose you have a solution with 15 projects, all using Newtonsoft.Json. Without CPM, updating it means changing 15 .csproj files.
With CPM, you just add this to Directory.Packages.props:
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
Now all projects use the new version automatically.
Conclusion
Central Package Management (CPM) in .NET makes life easier for teams working on solutions with many projects. It keeps package versions consistent, simplifies updates, and saves time. If you haven’t tried it yet, create a Directory.Packages.props file in your solution. You’ll quickly see the advantages. Happy Coding!
European Best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.


August 11, 2025 08:57 by
Peter
When you first encounter the Readonly keyword in C#, it seems straightforward, prevent fields from being reassigned after construction. But once you start applying it to reference types, things get more nuanced. We’ll break down what Readonly really means, especially when dealing with objects, how it behaves differently with value vs. reference types, and what developers should keep in mind to write safer, cleaner code.
What Does Readonly Actually Do?
In C#, the Readonly keyword:
- Can be applied to fields.
- Ensures the field can only be assigned during declaration or inside the constructor of the class/struct.
- Once assigned, the field can’t point to a different object.
public class User
{
public string Name { get; set; }
}
public class Account
{
private readonly User _user = new User();
public void ChangeUser()
{
// This is possible
_user.Name = "New Name";
// But this will result in compile-time error
_user = new User();
}
}
Misunderstanding:
A Readonly field of a reference type doesn’t make the object itself immutable, it only means the reference can’t be reassigned. You can still modify the object’s internal state.
Reference Types vs. Value Types with Readonly
Value Types:
readonly int number = 5;
// Compile-time error
number = 10;
With value types (like int, bool, struct), Readonly means you cannot change the value.
Reference Types:
readonly List<string> items = new List<string>();
// Possible
items.Add("Test");
// Compile-time error
items = new List<string>();
So, the object can still mutate , it’s the reference that’s locked.
Then, How to Make Reference Types Truly Immutable?
To make an object’s state immutable, you must:
- Avoid set accessors in properties.
- Make all fields Readonly.
- Use init accessors for initialization only.
- Don’t expose collection fields directly.
Example
public class User
{
public string Name { get; init; }
}
Readonly with Properties
While Readonly can be used on fields, it cannot be directly used on properties. But you can mimic the behavior using init accessor:
public string Role { get; init; } = "admin";
These make the property immutable after initialization.
European Best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.


August 4, 2025 08:11 by
Peter
This article guides you through creating a simple Employee Management System with CRUD functionality using.
- Backend: ASP.NET Core Web API
- Frontend: React.js
- Database: SQL Server (via Entity Framework Core)
Step 1. Backend Setup - ASP.NET Core Web API
1.1. Create Project
Run this command on bash.
dotnet new webapi -n EmployeeAPI
cd EmployeeAPI
1.2. Add EF Core Packages
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools
1.3. Create Employee Model
// Models/Employee.cs
namespace EmployeeAPI.Models
{
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public string Department { get; set; }
public decimal Salary { get; set; }
}
}
1.4. Create DbContext
// Data/EmployeeContext.cs
using Microsoft.EntityFrameworkCore;
using EmployeeAPI.Models;
namespace EmployeeAPI.Data
{
public class EmployeeContext : DbContext
{
public EmployeeContext(DbContextOptions<EmployeeContext> options)
: base(options)
{
}
public DbSet<Employee> Employees { get; set; }
}
}
1.5. Register DbContext in Program.cs
builder.Services.AddDbContext<EmployeeContext>(options =>
options.UseSqlServer(
builder.Configuration.GetConnectionString("DefaultConnection")
)
);
1.6. Add Connection String to appsettings.json
"ConnectionStrings": {
"DefaultConnection": "Server=YOUR_SERVER;Database=EmployeeDb;Trusted_Connection=True;"
}
using Microsoft.AspNetCore.Mvc;
using EmployeeAPI.Data;
using EmployeeAPI.Models;
using Microsoft.EntityFrameworkCore;
[ApiController]
[Route("api/[controller]")]
public class EmployeesController : ControllerBase
{
private readonly EmployeeContext _context;
public EmployeesController(EmployeeContext context) => _context = context;
[HttpGet]
public async Task<ActionResult<IEnumerable<Employee>>> GetEmployees() =>
await _context.Employees.ToListAsync();
[HttpGet("{id}")]
public async Task<ActionResult<Employee>> GetEmployee(int id)
{
var emp = await _context.Employees.FindAsync(id);
return emp == null ? NotFound() : emp;
}
[HttpPost]
public async Task<ActionResult<Employee>> CreateEmployee(Employee emp)
{
_context.Employees.Add(emp);
await _context.SaveChangesAsync();
return CreatedAtAction(nameof(GetEmployee), new { id = emp.Id }, emp);
}
[HttpPut("{id}")]
public async Task<IActionResult> UpdateEmployee(int id, Employee emp)
{
if (id != emp.Id)
return BadRequest();
_context.Entry(emp).State = EntityState.Modified;
await _context.SaveChangesAsync();
return NoContent();
}
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteEmployee(int id)
{
var emp = await _context.Employees.FindAsync(id);
if (emp == null)
return NotFound();
_context.Employees.Remove(emp);
await _context.SaveChangesAsync();
return NoContent();
}
}
1.7. Run Migrations
dotnet ef migrations add InitialCreate
dotnet ef database update
Step 2. Frontend Setup - React.js
2.1. Create React App
npx create-react-app employee-ui
cd employee-ui
2.2. Install Axios
npm install axios
2.3. Create API Service
// src/services/employeeService.js
import axios from 'axios';
const API_URL = 'https://localhost:5001/api/employees';
export const getEmployees = () => axios.get(API_URL);
export const getEmployee = (id) =>
axios.get(`${API_URL}/${id}`);
export const addEmployee = (data) =>
axios.post(API_URL, data);
export const updateEmployee = (id, data) =>
axios.put(`${API_URL}/${id}`, data);
export const deleteEmployee = (id) =>
axios.delete(`${API_URL}/${id}`);
JavaScript
2.4. Main Component Example
// src/App.js
import React, { useEffect, useState } from 'react';
import * as employeeService from './services/employeeService';
function App() {
const [employees, setEmployees] = useState([]);
const [form, setForm] = useState({ name: '', department: '', salary: '' });
const [editId, setEditId] = useState(null);
const fetchData = async () => {
const res = await employeeService.getEmployees();
setEmployees(res.data);
};
useEffect(() => {
fetchData();
}, []);
const handleSubmit = async (e) => {
e.preventDefault();
if (editId) {
await employeeService.updateEmployee(editId, form);
} else {
await employeeService.addEmployee(form);
}
setForm({ name: '', department: '', salary: '' });
setEditId(null);
fetchData();
};
const handleEdit = (emp) => {
setForm(emp);
setEditId(emp.id);
};
const handleDelete = async (id) => {
await employeeService.deleteEmployee(id);
fetchData();
};
return (
<div>
<h2>Employee Management</h2>
<form onSubmit={handleSubmit}>
<input
value={form.name}
onChange={(e) => setForm({ ...form, name: e.target.value })}
placeholder="Name"
required
/>
<input
value={form.department}
onChange={(e) => setForm({ ...form, department: e.target.value })}
placeholder="Department"
required
/>
<input
value={form.salary}
onChange={(e) => setForm({ ...form, salary: e.target.value })}
placeholder="Salary"
required
type="number"
/>
<button type="submit">{editId ? 'Update' : 'Add'}</button>
</form>
<ul>
{employees.map((emp) => (
<li key={emp.id}>
{emp.name} ({emp.department}) - ${emp.salary}
<button onClick={() => handleEdit(emp)}>Edit</button>
<button onClick={() => handleDelete(emp.id)}>Delete</button>
</li>
))}
</ul>
</div>
);
}
export default App;
Step 3. Enable CORS in .NET Core
builder.Services.AddCors(options =>
{
options.AddPolicy("AllowReactApp", policy =>
policy.WithOrigins("http://localhost:3000")
.AllowAnyMethod()
.AllowAnyHeader());
});
app.UseCors("AllowReactApp");
Step 4. Run the Projects
Run backend
dotnet run
Run frontend
npm start
Output
A simple UI to.
- List employees
- Add a new employee
- Edit existing employee
- Delete employee
Summary
This full-stack CRUD project demonstrated how to.
- Create and expose RESTful APIs in ASP.NET Core
- Connect SQL Server using EF Core
- Consume those APIs in React
- Use Axios for API calls
- Enable CORS between frontend and backend
European Best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.
