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:
- HelloWorldApp.Entities
- HelloWorldApp.Repositories
- 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:
- HelloWorldApp.Services
- 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:
- HelloWorldApp.Models
- 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.
Thanks for the example… but Google blocks de download link for pishing alert 🙁
Thanks for pointing it out. I have removed the link and posted an update.