ASP.NET MVC
custom classes
web development
programming
software architecture

Where can I put custom classes in ASP.NET MVC?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In ASP.NET MVC, custom classes can technically live anywhere in the project as long as the namespace is correct and the file is compiled. The better question is not "where are you allowed to put them" but "where should they go so the project stays understandable."

A good MVC project organizes classes by responsibility, not by convenience. If everything lands in Models or Helpers, the application compiles, but the architecture slowly turns opaque.

Use folders that match responsibility

The classic MVC folders are only the starting point. Controllers belong in Controllers, Razor views belong in Views, and model classes usually belong in Models. Beyond that, you should create folders for the kinds of custom classes your application actually uses.

A common structure looks like this:

text
1/Controllers
2/Models
3    /Entities
4    /ViewModels
5/Services
6/Repositories
7/Infrastructure
8/Filters
9/Extensions

This structure is easy to navigate because each folder answers a clear question:

  • 'Entities or domain models represent business data'
  • 'ViewModels shape data for a specific page or form'
  • 'Services hold application logic'
  • 'Repositories isolate persistence concerns'
  • 'Infrastructure contains cross-cutting concerns such as caching or email'
  • 'Filters hold MVC action filters and authorization attributes'

ASP.NET MVC does not require these folder names, but conventions like this reduce friction for the next developer.

Keep view models and domain models separate

One of the most common mistakes is putting every class into a single Models folder and using the same class for both persistence and view rendering. That quickly creates coupling between the UI and the data layer.

A cleaner setup is to separate view models from domain or entity models:

csharp
1namespace MyApp.Models.ViewModels
2{
3    public class CheckoutViewModel
4    {
5        public string CustomerName { get; set; }
6        public decimal Total { get; set; }
7        public bool CanSubmit { get; set; }
8    }
9}

Then keep service logic somewhere else:

csharp
1namespace MyApp.Services
2{
3    public class InvoiceService
4    {
5        public decimal CalculateTotal(decimal subtotal, decimal taxRate)
6        {
7            return subtotal + (subtotal * taxRate);
8        }
9    }
10}

This separation keeps controllers thin and makes the application easier to test.

Put business logic outside controllers

Controllers should coordinate a request, not own all the business rules. If a controller is calculating totals, sending email, querying multiple repositories, and formatting output, that code belongs in services or other supporting classes.

csharp
1using System.Web.Mvc;
2using MyApp.Models.ViewModels;
3using MyApp.Services;
4
5namespace MyApp.Controllers
6{
7    public class OrdersController : Controller
8    {
9        private readonly InvoiceService _invoiceService = new InvoiceService();
10
11        public ActionResult Summary()
12        {
13            var total = _invoiceService.CalculateTotal(100m, 0.13m);
14
15            var model = new CheckoutViewModel
16            {
17                CustomerName = "Ada",
18                Total = total,
19                CanSubmit = true
20            };
21
22            return View(model);
23        }
24    }
25}

Once the logic is moved out, the controller becomes easier to read and unit-test.

Consider a separate class library for larger projects

For small applications, putting custom classes into the MVC project is fine. For larger systems, a separate class library often makes more sense. Domain models, services, repository interfaces, and shared utilities can live outside the web project so they are reusable and easier to test without the MVC host.

This is especially helpful when:

  • multiple web apps share the same business logic
  • background jobs use the same services
  • you want a cleaner boundary between web concerns and domain concerns

The MVC project then becomes a presentation layer instead of the place where every concern accumulates.

Common Pitfalls

  • Using Models as a dumping ground for unrelated classes with very different responsibilities.
  • Putting business rules directly into controllers because it feels faster in the short term.
  • Creating vague folders such as Helpers or Utils instead of naming folders by actual responsibility.
  • Mixing persistence models and view models until UI concerns leak into the data layer.
  • Overengineering a small MVC app into too many projects before the complexity actually justifies it.

Summary

  • Custom classes can technically go anywhere in an ASP.NET MVC project, but conventions matter.
  • Organize classes by responsibility, not by convenience.
  • Separate view models, domain models, services, repositories, and infrastructure concerns.
  • Keep business logic out of controllers whenever possible.
  • Move shared or complex logic into separate class libraries when the application grows.

Course illustration
Course illustration

All Rights Reserved.