Overall Architecture
In these sections of the nopCommerce Developer Documentation, we will broadly cover the overall architecture of nopCommerce. Detailed descriptions of each component will be described in later sections of the developer guide.
Note that this part is an introductory overview. A more detailed discussion will come later in the guide. Depending on your experience level, these overviews may be enough to get you going!
Repository
nopCommerce implements a repository pattern as part of its data access strategy. For example, EfRepository<T>
implements IRepository<T>
, which declares interface methods such as T GetById()
, void Insert(T)
, void Update(T)
, and IQueryable<T> Table { get; }
. Almost every table will have an associated repository.
As mentioned previously, almost all classes that are services (aka "service classes" such as the BlogService
or CustomerService
in Nop.Services) hold at least one private reference to a repository. Most plugins will contain repository references as well.
When first exploring the nopCommerce code base, a potentially confusing thing about the repositories is the way they are instantiated. Normally a developer can easily navigate from an MVC controller to the implementation details of a service class. For example, let's say you are curious about _orderTotalCalculationService
here:
public class CheckoutController : BasePublicController
{
//...
private IOrderTotalCalculationService _orderTotalCalculationService;
//...
}
In Visual Studio, you can right click on IOrderTotalCalculationService
to examine the interface definition:
namespace Nop.Services.Orders
{
public interface IOrderTotalCalculationService
{
//...
}
}
... Or you can find all references to IOrderTotalCalculationService
and finally read the code for the actual concrete class that implements the interface:
namespace Nop.Services.Orders
{
public class OrderTotalCalculationService : IOrderTotalCalculationService
{
//...
}
}
Not so with the repositories! That is, you will never find a class that implements (for example) IRepository<Order>
or that inherits from EfRepository<Order>
. So how can the service classes receive instances of these repositories?
It happens through the magic of "open generics" the DI container. In Nop.Web.Framework.DependencyRegistrar
, there is a single line that tells the DI container how to instantiate all IRepository<T>
:
builder.RegisterGeneric(typeof(EfRepository<>)).As(typeof(IRepository<>));
In general, the repository layer is a very “thin” layer, so there’s not much else to say in this introduction to the repositories.
Interesting reading
Repository pattern – Two thought-provoking articles by Ayende Rahein about the repository pattern: The evils of the repository abstraction layer and Repository is the new Singleton. A nice discussion about thin repositories and ORMs: Say No to the Repository Pattern in your DAL
Generic registration in DI containers - A discussion about open generics in DI containers.