Layering of an application's codebase is a widely accepted technique to help reduce complexity and improve code reusability. To achieve layered architecture, ASP.NET Boilerplate follows the principles of Domain Driven Design. In Domain Driven Design there are four fundamental layers:
There may be additional layers added as necessary. An example being:
These are all common layers of a domain-centric architecture. There may be minor differences based on implementation.
Overview of layers and structures are shown below:
Layers |
|
---|---|
Presentation | View Models (Javascript), Views (HTML/CSS), Localization, Navigation, Notifications |
Web | Web API Controllers, MVC Controllers, OData, ASP.NET Core |
Application | Application Services, DTOs, DTO Mappers, Authorization, Session, Audit Logging |
Domain (Core) | Entities, Value Objects, Repositories, Domain Services, Unit of Work, Domain Events |
Infrastructure | ORM (EntityFramework, NHibernate), DB Migrations, Background Jobs |
Others (common) |
|
Dependency Injection, Logging, Caching, Settings... |
Here is a solution with five projects for a simple layered application:
A layer can be implemented as one or more assemblies. It may be good to create more than one assembly for third-party dependencies (like EntityFramework here) for larger projects. Also, there may be bounded contextes where every context has it's own layers.
Domain Layer is where all business rules should be implemented.
Entities represent data and operations of the business domain. Generally they are mapped to database tables in practice.
Repositories are collection-like objects and are used to retrieve and persist entities on a data source (database). Domain Layer defines repositories, but does not implement them. They are implemented in the Infrastructure Layer.
Domain Events are used to define domain-specific events as well as to trigger and handle them. Domain services work with entities (and other domain objects) and implement business rules which do not belong within a single entity.
Unit of Work is a design pattern used to manage database connection and transaction, track entity changes and save changes to a data store. It's defined in domain layer, but implemented in infrastructure layer.
This layer should be independent of third-party libraries as much as possible.
Application Layer contains application services those are used by the Presentation Layer. An application service method can receive a DTO (Data Transfer Object) as input, uses this input to perform some specific domain layer operation, and may return another DTO, if needed. It should not receive or return entities. An application service method is generally considered a Unit of Work. User input validation is also implemented in this layer. It's suggested to use a tool for mapping entities to DTOs such as the AutoMapper library. We have also session here to obtain information on current user.
While Domain Layer defines interfaces for repositories, unit of work and other services, Infrastructure Layer implements those interfaces. It implements repositories using ORM tools like NHibernate or EntityFramework. ASP.NET Boilerplate provides base classes to work with these two ORM frameworks. Infrastructure Layer is used to abstract away dependencies on third-party libraries from the other layers. Database Migrations can be used here as well.
Beside database access, we may have abstractions for service providers. For example, we may use a vendor to send SMS messages. We can define an interface in domain or application layer to abstract it from our code. Then we can implement that interface in the infrastructure layer.
Web Layer is implemented using ASP.NET MVC, Web API and ASP.NET Core. Two different approaches can be implemented here: Single-Page Applications or Multi-Page Applications. Startup templates support both of them.
In a Single-Page Application (SPA) all resources are loaded once (or a core resource is loaded and others are lazy loaded when needed) to the client (browser) and then all subsequent interaction with the server is made using AJAX calls. HTML code is generated on the client-side with data received from server. The entire page is never refreshed; views are just swapped in and out as necessary. There are many Javascript SPA frameworks, such as AngularJs, BackboneJs, and EmberJs. ASP.NET Boilerplate can work with any of them, but provides samples and some helper mechanisms to easily work with Angular.
In a Multi-Page (Classic) Application (MPA), client makes a request to the server, the server side code (ASP.NET MVC Controllers in general) gets data from the database, and Razor views generate HTML. These generated pages are sent back to the client to display it. Each new page results in a full page refresh. Client then can make additional AJAX requests for better user experience.
SPA and MPA involve completely different architectures. An admin panel is a perfect candidate for a SPA. On the other hand, a blog better fits to the MPA model since it is desirable to have it crawled by search engines. Even though there are tools to help make SPAs visible to search engines, the general approach is as such for the time being.
SignalR is a perfect tool to send push-notifications from the server to the client. It can be used to provide a rich, real-time experience to the user.
There are many Javascript libraries & frameworks on the client side. jQuery is the most popular in this area with thousands of free plug-ins. There are also tools/frameworks that make it easy to work with HTML & CSS. For example, Twitter Bootstrap is a very popular HTML/CSS framework option.
ABP provides infrastructure to automatically create a Web API Layer from your application services and easily use it with Javascript (see documentation). Additionally, it provides infrastructure to manage application menus, localization, and language switching. Also included is a simple and unified Javascript API to simplify showing system messages and notifications.
ASP.NET Boilerplate automatically handles exceptions in server-side and returns an appropriate response to the client.
ASP.NET Boilerplate uses and supports Dependency Injection through the Castle Windsor framework. It also uses Log4Net for logging server-side, however, easily supports swapping in other logging libraries without code change by the help of Castle's abstract logging facility.
ASP.NET Boilerplate leverages some of the best frameworks/libraries in addition to its own classes and systems to provide a great infrastructure to build web applications with an NLayer architecture. It also has templates that can be used to easily create a layered solution as a starting point for your application.