nopCommerce is an open-source project based on .NET technologies with understandable architecture. It is easily customizable and pluggable that enables the development and integration of any features, extensions and themes. Every .NET developer may download the source code and start creating any eCommerce project.
To help developers navigate through the source code, the article has been prepared based on the training course that the nopCommerce team has developed. Here we consider an architecture and source code overview, as well as an MVC pattern.
Architecture overview and source code organization
The nopCommerce source code and architecture are quite easy to understand. The solution structure is pretty clear, so you should have no difficulties learning the codebase.
Our architecture follows the separation of concerns principle, which helps us keep the growing codebase organized so that developers can easily find where a particular functionality is implemented.
Most of the projects, directories, and files are named so that you can get a rough idea of their purpose. For example, there is no need to look inside the project named “Nop.Plugin.Payments.PayPalStandard" to guess what it does.
So, when the nopCommerce solution is opened in Visual Studio, first, you see the following folder structure.
nopCommerce is a multi-project solution, which means each project is considered to reside in a particular layer of the application. Next, a scheme that illustrates the relationships will be provided.
The directory “Libraries" contains 3 projects: "Nop.Core", "Nop.Data", and "Nop.Services". This is the innermost layer in the nopCommerce architecture system. It is the core of the application. All the data access logic and business classes reside inside this directory.
The "Nop.Core" project contains a set of core classes, such as domain entities, caching, events, and helper classes.
In the “Domain" folder, the business objects can be seen. For example, the “Customer" entity or “Order" entity. So, here, you can find all the entities we use. In this directory, you can also see setting classes, such as “CatalogSettings" or “ForumSettings".
The "Nop.Core" project is kind of a centre of the nopCommerce architecture. This project has no dependencies on other projects in the solution. The classes of "Nop.Core" are shared with the entire solution.
A scheme representing the nopCommerce architecture is presented. In this scheme, you can see that the "Nop.Core" project is related to the Business logic layer. All the other parts of nopCommerce are connected to this layer.
The next project is "Nop.Data". The "Nop.Data" project contains a set of classes and functions for reading from a database and writing to it. Therefore, it represents the Data access layer. The "Nop.Data" project helps us separate data-access logic from the business objects, which can be seen in "Nop.Core".
In the “DataProviders" folder, you can see all the data providers we use in nopCommerce: Microsoft SQL Server, MySql, and PostgreSQL data providers.
nopCommerce uses the Linq2DB Code-First approach. Code-First allows us to define entities in the source code (they can be seen in the " Nop.Core" project) and then use “Linq2DB" and “FluentMigrator" to generate the database from these C# classes. That's why it's called “Code-First." You can then query your objects using LINQ which is Language Integrated Query. LINQ translates to SQL behind the scenes and is executed against the database.
nopCommerce uses fluent code API to customize the persistence mapping. You can see all the mapping classes in the “Builder" folder of the “Mapping" directory. If you open, for example, the "BlogPostBuilder" class, you may see this class allows us to configure each column of the “BlogPost" table in the database as we need. Each entity has such a builder class.
Then, the next important part of the "Nop.Data" project is Migrations. As you know, migrations allow us to alter the database schema. This is an alternative to creating lots of SQL scripts that have to be executed manually to apply any database changes.
The "Nop.Data" project also contains the other interfaces and classes used to connect to the database. Unlike the "Nop.Core" project, "Nop.Data" has no dependencies on any other project in the solution.
The other important part is the "Nop.Services" project. It contains a set of core services, business logic, validations, and calculations related to the data. So the "Nop.Services" project is related to the Business logic layer. This project has a dependency on all other projects that belong to the Application Core: "Nop.Core" and "Nop.Data".
This project provides data access functionality for the Presentation layer. This layer contains service classes and follows a repository pattern to expose its functionalities.
The folder names are self-descriptive. If we look at the Blogs folder, for example, it contains a service that helps us get, insert, and delete blog posts in the repository. It also contains an interface for this service, allowing to change the implementation without updating the code. The idea is that when you need to change how the service handles some functions, all you have to do is create a new class that implements IBlogService and then register it with the NopStartup. So you don’t have to touch any of the controllers that use that interface.
To look at plugin projects the “Plugins" folder should be opened. A plugin is a set of components adding specific capabilities to a nopCommerce store. In other words, plugins are used to extend the functionality of nopCommerce. Each plugin is a separate project containing a feature.
Plugins are classified into different groups. For example, payment methods (such as PayPal), tax providers (like Avalara), shipping rate computation methods (such as UPS or ShipStation), widgets (such as google analytics), and many others. As it can be seen, there are a lot of plugins coming out of the box. Any feature that is necessary to be added to a nopCommerce store, can be implemented in a plugin without touching the source code.
Physically, plugins are located at the root of the solution. But plugins’ DLLs are automatically copied to the “Presentation\Nop.Web\Plugins" directory, which is used for already deployed plugins. This allows plugins to contain some external files, such as static content (CSS or JS files), without having to copy files between projects to run the project.
On our scheme, you can see that plugins touch all the layers. This is because each plugin can potentially include its own data access, business logic, and UI layers at the same time.
Have a look at the “Presentation" folder. Its content represents the presentation or user interface layer.
"Nop.Web" is an MVC web application project. "Nop.Web" provides a public interface and an administration panel included as an area. This is the application that you actually run. It is the startup project of the nopCommerce solution.
This project contains controllers, factories, models, views, and other stuff related to the presentation layer. The "Nop.Web" project connects to "Nop.Services" to retrieve data, make calculations, and use business logic.
And " Nop.Web.Framework" is a class library project containing some common presentation things for the "Nop.Web" project.
The last folder obviously contains tests. Unit tests are automated tests written and run by developers to ensure that an application section meets its design and behaves as intended. During development, we code criteria or results known to be good into the test to verify the application function’s correctness. During test case execution, the framework logs tests that fail any criterion and report them in a summary. The testing system in nopCommerce includes tests for the "Nop.Core", "Nop.Data", "Nop.Services", and "Nop.Web" projects.
We also would like to note that nopCommerce utilizes asynchronous programming. Each controller or service method is asynchronous. And the “async" modifier indicates that. Such methods return “Task" objects that represent asynchronous operations.
When an asynchronous method is called, it requires the “await" operator placed in front of it. This “await" operator suspends evaluation of the enclosing async method until the asynchronous operation represented by its operand is complete. The “await" operator doesn't block the thread that evaluates the async method. When the asynchronous operation is complete, the “await" operator returns the result of the operation, if any. “Await" can only be used inside an async method.
This way, by implementing the task asynchronous programming model in nopCommerce, we achieved great performance enhancements.
MVC pattern in nopCommerce
nopCommerce implements the “Model-View-Controller" (MVC) design pattern in its architecture. This design pattern allows us to decouple the user interface (which is View), data (which is Model), and application logic (which is Controller). This pattern helps achieve separation of concerns.
Using the MVC pattern means that requests are routed to the Controller responsible for working with the Model to perform actions and/or retrieve data. The Controller chooses the View to display and provides it with the Model. The View renders the final page based on the data in the Model.
This delineation of responsibilities helps us scale the nopCommerce app in terms of complexity because it's easier to code, debug, and test something (Model, View, or Controller) that has a single job.
Example of applying MVC
Here we open the “BlogPost" view from the “Nop.Web" project. This view uses the Razor view engine to embed .NET code in HTML markup. It contains minimal logic, but any logic in this view is related to presenting content. We don’t perform a great deal of logic in view files.
According to the MVC pattern, all the logic related to the View should be placed in the appropriate controller. Controllers are the components that handle user interaction, work with models, and ultimately select a view to render. In an MVC application, a view only displays information; a controller handles and responds to user input and interaction. In the MVC pattern, the Сontroller is the initial entry point responsible for selecting which model types to work with and which view to render.
The name of the controller, in this case, is “BlogController". Here we can find the “BlogPost" action method that retrieves data, populates the model with this data, and then returns the needed view.
This view uses the received model to present content. For example, this iteration displays the tags cloud on the page.
Let’s go back to our controller. Controllers shouldn't be overly complicated with too many responsibilities. So we keep controller logic from becoming overly complex and push business logic out of the controller. If we dig deeper and fall into the “BlogService," we will see that the business logic related to retrieving data from the database is actually placed here. The “GetBlogPostById" method accesses the repository to get data. But this method is not as huge as “GetAllBlogPosts," for example.
This way, we briefly considered the implementation of the MVC pattern in nopCommerce. During the training course, we will talk about it in more depth.
From the article, you got acquainted with the nopCommerce structure and gained an insight into its architecture. This is the core of the nopCommerce platform and contains essential functionalities and business logic. These basics are explained in detail and completed with information about additional functionalities and principles in our training course.
The nopCommerce online course is compiled by the nopCommerce core developers based on our 13 years of experience, and questions frequently asked within the premium support services and community forums.
It has been designed to cover the main aspects of developing an eCommerce store and teach to:
- quickly run and configure websites of any complexity on nopCommerce;
- customize nopCommerce to fit unique business requirements;
- create integrations with third-party software;
- create and customize plugins and themes;
- avoid common mistakes when setting up and customizing nopCommerce;
- follow the best practices and use the latest development experience on nopCommerce.
Visit the training course content page to look at topics that are covered, as well as the conditions of starting the course. If you are ready to start deploying and customizing you may get started by downloading the package with the source code.