Project structure for a large ASP.NET MVC application

ASP.NET MVC is a presentation framework. MVC stands for Model-View-Controller. Model gives a notion that it is related to data access. However, it is just a data abstraction for the view. It can be thought of a ViewModel.

Apart from MVC, a large ASP.NET application deals with services. It also deals with data access. We need a good project structure. In the post, we build a simple Hello world project. With the assumption that it is a complex application. We retrieve a greeting from the database and display it in the UI.

Data Access Layer

Data access layer has three assemblies:

  1. HelloWorldApp.Entities
  2. HelloWorldApp.Repositories
  3. HelloWorldApp.Repositories.Contracts

Greeting class

We define an entity, Greeting.

namespace HelloWorldApp.Entities
{
    public class Greeting
    {
        public string Text { get; set; }
    }
}

IGreetingRepository interface

We have repository classes for data access. For each repository class, we create a corresponding interface.

namespace HelloWorldApp.Repositories.Contracts
{
    public interface IGreetingRepository
    {
        IEnumerable<Greeting> Get();
    }
}

GreetingRepository class

Our repository class implements the interface defined earlier.

namespace HelloWorldApp.Repositories
{
    public class GreetingRepository : IGreetingRepository
    {
        public IEnumerable<Greeting> Get()
        {
            var greeting = new Greeting();
            greeting.Text = "Hello World";
            yield return greeting;
        }
    }
}

Business Logic Layer

The business logic layer has two assemblies:

  1. HelloWorldApp.Services
  2. HelloWorldApp.Services.Contracts

We do not need the service layer, especially for simple data access. But if the data from relation DB is combined with data from other services, we need service classes.

IGreetingService interface

For each service class, we define an interface.

namespace HelloWorldApp.Services.Contracts
{
    public interface IGreetingService
    {
        GreetingModel GetGreeting();
    }
}

GreetingService class

Our service class implements the interface defined earlier.

namespace HelloWorldApp.Services
{
    public class GreetingService : IGreetingService
    {
        public GreetingService(IGreetingRepository repository)
        {
            _repository = repository;
        }

        public GreetingModel GetGreeting()
        {
            var model = new GreetingModel();
            var greeting = _repository.Get().First();
            model.Greeting = greeting.Text;
            return model;
        }

        private IGreetingRepository _repository;
    }
}

Presentation Layer

The presentation layer has two assemblies:

  1. HelloWorldApp.Models
  2. HelloWorldApp

GreetingModel class

We define a Model for our view. This model looks similar to the entity defined earlier. Entity classes have database mapping information embedded in them. Models are more simple. They don’t need to look like the database table. Optionally, some models have model binder. Model binders take information from a HTTP request and convert it into models or objects.

namespace HelloWorldApp.Models
{
    public class GreetingModel
    {
        public string Greeting { get; set; }
    }
}

HomeController class

Our controller class has the Index action method. The action gets a greeting model from the service class. It passes the model to the view.

namespace HelloWorldApp.Controllers
{
    public class HomeController : Controller
    {
        public HomeController(IGreetingService service)
        {
            _service = service;
        }
        
        public ActionResult Index()
        {
            var model = _service.GetGreeting();
            return View(model);
        }

        private IGreetingService _service;
    }
}

Index view

The view accepts a GreetingModel and knows how to render it in HTML.

@model HelloWorldApp.Models.GreetingModel
<body>
    <div> 
        @Model.Greeting
    </div>
</body>

Design idea

We organize the project structure of large applications into layers. Each layer interacts with the layer beneath it. MVC is the topmost layer. Service layers interact with external APIs and other data access layers.

Each layer has one or more assemblies. We usually split the interface and implementation into separate assemblies. This aids unit testing. Unit tests reference only the interface assemblies. We did not cover Dependency injection. The unit tests receive the actual classes to test using Dependency injection. Pass mocks for all other classes.

Download the complete source code. HelloWorldApp

UPDATE: I have removed the download link as Google thinks it is phishing. I don’t work on .NET these days. So, I have lost the source code for this.

Related Posts

2 thoughts on “Project structure for a large ASP.NET MVC application

Leave a Reply

Your email address will not be published.