Introduction
In this article, we will see the Best practice to make your project cleaner in .NET
Before we start, please take a look at my last article on Best practice to make your project cleaner in .NET CORE.
Let's get started.
The clean project principles are mostly the same, but in .NET Framework there are some differences in structure, DI, and configuration because:
-
There's no Program.cs
with minimal hosting model.
-
You often work with ASP.NET MVC 5, Web API 2, or WCF instead of ASP.NET Core.
-
Dependency Injection and configuration are not built-in — you use NuGet packages (e.g., Autofac, Unity, Ninject).
Here’s the .NET Framework–specific best practices:
1. Keep a Layered Architecture
Example for ASP.NET MVC 5 / Web API 2:
MyApp.sln
├─ MyApp.Web // MVC or Web API project (Controllers, Views)
├─ MyApp.Application // Service layer (business logic, DTOs)
├─ MyApp.Domain // Entities, enums, interfaces
├─ MyApp.Infrastructure // EF6, repositories, external integrations
└─ MyApp.Tests // Unit & integration tests
Note: You can still do feature-based folders inside Web
or Application
.
2. Use Dependency Injection (Manually Registered)
In .NET Framework, you add a DI container manually, for example Autofac:
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterType<OrderService>().As<IOrderService>();
builder.RegisterType<OrderRepository>().As<IOrderRepository>();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
Note: Do this in Global.asax
→ Application_Start()
.
3. Keep Controllers Thin
Same as in Core: controllers only handle HTTP flow — move logic into services.
4. Use ViewModels & DTOs
Mapper.Initialize(cfg => cfg.CreateMap<Order, OrderDto>());
5. Centralize Exception Handling
In MVC/Web API, use:
public class GlobalExceptionFilter : IExceptionFilter {
public void OnException(ExceptionContext filterContext) {
// log error
filterContext.Result = new ViewResult { ViewName = "Error" };
filterContext.ExceptionHandled = true;
}
}
Register in FilterConfig.cs
6. Keep Configuration Out of Code
var settingValue = ConfigurationManager.AppSettings["MySetting"];
Or use Settings.settings
file for auto-generated config classes.
7. Avoid Magic Strings / Numbers
Same principle:
public static class Roles {
public const string Admin = "Admin";
}
8. Apply SOLID
Even in .NET Framework — especially important because older projects tend to get “God classes”.
9. Use Filters & Action Attributes
Instead of putting auth/logging/validation code in controllers:
10. Use EF6 Best Practices
-
Avoid lazy loading unless needed.
-
Use AsNoTracking()
for queries that don’t need entity tracking.
-
Keep DB logic in repositories or a dedicated DAL.
11. Unit Testing Without Core’s Built-in DI
12. Keep Global.asax
Clean
-
Move route configs to RouteConfig.cs
.
-
Bundle/minify in BundleConfig.cs
.
-
Register filters in FilterConfig.cs
.
-
Only call setup methods in Application_Start()
.
13. Static Analysis & Style Rules
14. Async in ASP.NET
public async Task<ActionResult> GetOrders() {
var orders = await _orderService.GetOrdersAsync();
return Json(orders, JsonRequestBehavior.AllowGet);
}
15. Document Your APIs
Conclusion
Here we tried to cover Best practice to make your project cleaner in .NET