Build e-commerce application on .NET Framework


In this article, we consider the stack of technologies used in nopCommerce, the most popular ASP.NET shopping cart in the world. nopCommerce has been developed and supported by professionals since 2008.

We, the nopCommerce team, always try to keep nopCommerce running on the latest technologies to offer the best experience possible to our users. That's why nopCommerce is the leading ASP.NET-based open-source eCommerce platform for now.

nopCommerce is a fully customizable shopping cart, stable, secure, and extendable. From downloads to documentation, nopCommerce.com offers a comprehensive base of information, resources, and support from the nopCommerce community.

nopCommerce version runs on .NET Core. Since it's cross-platform it can be run on Windows, Linux, or Mac OS. nopCommerce also supports different database types. So let's start by describing the data access layer.

Databases

On the Data access layer, you are allowed to use Microsoft SQL Server, MySQL, and PostgreSQL as backend databases.

  1. SQL Server is Microsoft's full-featured relational database management system.
  2. MySQL is the world's most popular open-source database. With its proven performance, reliability, and ease of use, MySQL has become the leading database choice for web-based applications.
  3. PostgreSQL is a powerful, open-source object-relational database system with over 30 years of active development that has earned a strong reputation for reliability, feature robustness, and performance.

The possibility to use all these databases is coming out of the box so you don't need lots of extra configuration to set this up.

If you look at the source code, you see the appropriate data providers: PostgreSqlDataProvider, MySqlDataProvider, MsSqlDataProvider in the Nop.Data project.

Redis

Next, nopCommerce uses Redis. As you may know, Redis is an open-source, in-memory data structure store, used as a database, cache, and message broker. Redis is applied to distributed applications, for example, with web farms scenarios. Using Redis allows us to store old data as an in-memory cache dataset. This approach significantly boosts the speed and performance of the application.

This is the piece of code from the appsettings.json file that allows you to set up Redis in nopCommerce:

"DistributedCacheConfig": {
    "DistributedCacheType": "redis",
    "Enabled": false,
    "ConnectionString": "127.0.0.1:6379,ssl=False",
    "SchemaName": "dbo",
    "TableName": "DistributedCache"
  },

There are also another distributed cache types you can choose from:

This screenshot represents the distributed cache settings from the admin area -> App settings page.

Microsoft Azure

The next noteworthy technology that nopCommerce uses is Microsoft Azure. Azure is a public cloud computing platform with solutions including Infrastructure as a Service (IaaS), Platform as a Service (PaaS), and Software as a Service (SaaS) that can be used for services such as analytics, virtual computing, storage, networking, and much more. nopCommerce can be deployed on Azure using FTP, Visual Studio web deploy, or using Web platform installer.

Azure supports multiple instances of nopCommerce. It's great for any application scalability. Using this feature, you may not worry whether your site can handle a large number of visitors. Azure also allows us to use BLOB storage, distributed caching, and session management support.

This is the piece of code from the appsettings.json file that allows you to set up Azure BLOB storage in nopCommerce:

"AzureBlobConfig": {
    "ConnectionString": "",
    "ContainerName": "",
    "EndPoint": "",
    "AppendContainerName": true,
    "StoreDataProtectionKeys": false,
    "DataProtectionKeysContainerName": "",
    "DataProtectionKeysVaultId": ""
  },

It can also be set up from the admin area:

This screenshot represents the Azure BLOB storage settings from the admin area -> App settings page.

Business logic

Then, let's discuss the technologies we use in the nopCommerce Business logic layer.

Linq2DB

First of all, it's LINQ to DB, which is the LINQ database access library offering a simple, light, fast, and type-safe layer between objects and the database. In other words, it enables us to work with a database using .NET objects. It can map .NET objects to various numbers of database providers. You may choose between MS SQL Server, MySql server, and PostgreSQL.

So, LINQ to DB is kind of a bridge between the Business Logic layer and the Data layer.

If we analyze the code, we can easily find that each database is supported by its own class that implements the INopDataProvider interface and depends on the Linq2DB library:

Also, note that all work with table data is carried out through the IRepository interface. This IRepository interface implements methods to get, insert, delete entities, and more:

This approach commits us to control the creation of the table in the database.

FluentMigrator

To control the creation of the database objects we use the FluentMigrator library. FluentMigrator is a migration framework for .NET. Migrations are a structured way to alter the database schema and are an alternative to creating lots of SQL scripts that have to be run manually by every developer involved. Migrations solve the problem of evolving a database schema for multiple databases. For example, the developer's local database, the test database, and the production database. Database schema changes are described in classes written in C# that can be checked into a version control system.

To see how we use FluentMigrator in the code, open the CategoryBuilder class which represents the Category entity configuration for the database:

As a parameter of the MapEntity method, you can see the CreateTableExpressionBuilder class, which is the FluentMigrator class that allows us to apply special rules for entity mapping when creating this table.

Then, let's open the DataMigration class:

This class inherits from the abstract Migration class. You can create your own migrations which should also be derived from this abstract class.

So, as you can see, we use this class to migrate data from one version of nopCommerce to another. This way we add new records, new columns, or even delete columns. We also have such migration classes to migrate settings and local resources. In the past nopCommerce versions, we used SQL upgrade scripts to apply such changes to the database, which wasn't as handy as it is now.

Now, using the FluentMigrator library allows us to simplify the migration process to any database framework.

AutoMapper

The next library, which is introduced in this article, is AutoMapper. AutoMapper is a simple library that helps us to transform one object type to another. It is a convention-based object-to-object mapper that requires very little configuration. We need this library, for example, when it comes to retrieving entities from the database and populating the appropriate models.

To illustrate it, we open the StoreController of the admin area. Here we find the Edit() method which returns a view enabling a Store editing. In this method, as you can see, we retrieve the store from the database first:

Then, in the PrepareStoreModel() method there is just one line that maps the entity to a new model:

This is exactly why we need AutoMapper.

At the same time, in the AdminMapperConfiguration we have already configured how exactly the store entity should be mapped to the model:

Fluent Validation

The next library we discuss is Fluent Validation. It's a validation library for .NET that uses a fluent interface and lambda expressions for building validation rules. We need validation to ensure that data inserted satisfies defined formats and other input criteria during customer registration, creating and updating products and categories in the admin area, adding blog posts, etc.

Let's look closer. For example, the RegisterValidator class sets validation rules for RegisterModel which is used for customer registration:

In this class we see a rule saying that the Email field should not be empty, but if it is, the validator returns the "required" message to a customer. In addition, an inserted email should also match the email address criteria.

There are many other validation rules in this file.

ASP.NET Core internal dependency injection

As you may know, nopCommerce supports the dependency injection software design pattern, which is a technique for achieving Inversion of Control between classes and their dependencies. It allows nopCommerce to stay easy modifiable as it grows in size and complexity.

To achieve this we use the built-in ASP.NET Core internal dependency injection.

To illustrate the dependency injection in the code, let's look, for example, at the ProductService class:

Here we have many dependencies going into the constructor. If we look at the implementation of one of those dependencies, for example, at the CustomerService we see that it contains a bunch of dependencies as well:

And to resolve these dependencies we create the DependencyRegistrar class where the AddScoped() method registers such services as ProductService, CustomerService, and others:

So, using the ASP.NET Core internal dependency injection, we have a service container that takes on the responsibility of creating an instance of the dependency and disposing of it when it's no longer needed. And we can easily inject the service into the constructor of the class where it should be used.

Autofac

We also use the Autofac library which is an addictive Inversion of Control container for .NET. Autofac is one of the libraries we use right now, but, it's important to say, we use this library to only wrap the built-in Dependency Injection container from ASP.NET Core. That's why you can find out that the only file where we access the Autofac namespace is the Program class:

Look at the Main method where we override the factory used to create the service provider.

User interface

Further, let's see which libraries we use in the User interface layer.

Razor View Engine

Razor View Engine allows us to embed server-based code into web pages to produce HTML.

Let's look at the category page view:

Razor enables us to easily render the category name and to render the details like the description. It processes considering conditions, such as if the description is not empty we render the appropriate HTML code.

Using Razor we can also iterate and display subcategories or featured products.

jQuery

We also use jQuery which is a javascript library used to extend the UI&UX functionality of HTML pages. You can find the appropriate javascript files in the "js" folder in wwwroot:

jQuery DataTables and more

In addition, particularly, to display the data in tables in the admin area we use a DataTables plug-in for jQuery. Such tables look like this:

We also use a lot of other jQuery plugins so we don't need to reinvent the wheel and can concentrate on things that matter.