# Nopcommerce

> This skill should be used when the user asks to "create a nopCommerce plugin", "build a nopCommerce extension", "nopCommerce dependency injection", "nopCommerce Entity Framework", "nopCommerce admin plugin", "nopCommerce payment plugin", "nopCommerce widget", "publish to nopCommerce marketplace", or needs guidance on nopCommerce plugin development with .NET/C#.

- Skill: `biggora/nopcommerce` (Agent Skill, multi-file: 6 files)
- Install (CLI): `npx skillmds@latest add biggora/nopcommerce`
- Raw SKILL.md: https://api.skillmd.com/api/skills/biggora/nopcommerce/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: biggora (https://skillmd.com/u/biggora)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/biggora/nopcommerce

---


# nopCommerce Plugin Development

## Overview

nopCommerce is an open-source e-commerce platform built on ASP.NET Core and Entity Framework Core. It powers over 60,000 online stores worldwide and provides a fully modular, plugin-based architecture that allows developers to extend every aspect of the platform -- from payment processing and shipping to tax calculation, widgets, and admin functionality -- without modifying the core source code.

The platform follows a layered architecture with clear separation between presentation (Nop.Web), business logic (Nop.Services), data access (Nop.Data), and core domain (Nop.Core). Plugins operate as self-contained .NET class library projects that hook into this architecture through well-defined interfaces, dependency injection, and an event-driven system.

nopCommerce supports two database engines: Microsoft SQL Server and PostgreSQL. The data layer uses Linq2DB as its primary ORM (replacing Entity Framework Core in recent versions) with FluentMigrator for schema migrations. The admin area uses Razor views with Kendo UI components, and the public storefront supports fully customizable themes.

Plugin development requires familiarity with C#, ASP.NET Core, dependency injection, and the nopCommerce-specific abstractions for services, data access, and UI extension. The platform provides abstract base classes and interfaces that plugins implement to integrate with the core system.

Key architectural layers that plugins interact with:

- **Nop.Core** -- Domain entities, configuration classes, caching interfaces, event infrastructure, and helper utilities shared across all layers.
- **Nop.Data** -- The data access layer providing `IRepository<T>`, entity builders for schema mapping, FluentMigrator-based migrations, and the Linq2DB integration for custom queries.
- **Nop.Services** -- Business logic layer containing service interfaces and implementations for orders, customers, products, payments, shipping, taxes, localization, settings, scheduled tasks, and logging.
- **Nop.Web.Framework** -- MVC infrastructure including controller base classes, model binding, tag helpers, view component base classes, HTML helpers, validators, and security filters.
- **Nop.Web** -- The presentation layer hosting Razor views, themes, the admin panel, and the plugin runtime directory where compiled plugin DLLs are deployed.

## Plugin Structure

Every nopCommerce plugin lives in a directory under `Plugins/` in the solution root, following the naming convention `Nop.Plugin.{Group}.{Name}` -- for example, `Nop.Plugin.Payment.Stripe` or `Nop.Plugin.Widgets.GoogleAnalytics`. The plugin group determines how nopCommerce categorizes and displays the plugin in the admin panel.

### Project File (.csproj)

The plugin project file references nopCommerce core libraries and configures the build output to copy the compiled DLL into the correct runtime directory:

```xml
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <OutputPath>..\..\Presentation\Nop.Web\Plugins\Nop.Plugin.Misc.MyPlugin</OutputPath>
    <OutDir>$(OutputPath)</OutDir>
    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
  </PropertyGroup>
  <ItemGroup>
    <ProjectReference Include="..\..\Presentation\Nop.Web.Framework\Nop.Web.Framework.csproj" />
    <None Include="plugin.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>
</Project>
```

The `OutputPath` must point to `Presentation/Nop.Web/Plugins/{PluginName}` so the plugin DLL and its assets are available at runtime.

### Plugin Descriptor (plugin.json)

Every plugin requires a `plugin.json` file that declares metadata consumed by the nopCommerce plugin system:

```json
{
  "Group": "Misc",
  "FriendlyName": "My Custom Plugin",
  "SystemName": "Nop.Plugin.Misc.MyPlugin",
  "Version": "1.0.0",
  "SupportedVersions": [ "4.70" ],
  "Author": "Developer Name",
  "DisplayOrder": 1,
  "FileName": "Nop.Plugin.Misc.MyPlugin.dll",
  "Description": "A brief description of what the plugin does.",
  "LimitedToStores": [],
  "LimitedToCustomerRoles": [],
  "DependsOnSystemNames": []
}
```

The `SystemName` must match the assembly name exactly. `SupportedVersions` declares compatibility with specific nopCommerce versions and determines whether the plugin appears as installable in the admin.

### BasePlugin Class

Every plugin must contain a class that extends `BasePlugin`. This class provides the install and uninstall lifecycle hooks:

```csharp
public class MyPlugin : BasePlugin
{
    public override async Task InstallAsync()
    {
        // Create database tables, seed default settings, add locale resources
        await base.InstallAsync();
    }

    public override async Task UninstallAsync()
    {
        // Drop tables, remove settings, delete locale resources
        await base.UninstallAsync();
    }
}
```

Plugins that implement specific platform features (payment, shipping, tax, widgets) extend specialized interfaces instead of or in addition to `BasePlugin`. For example, a payment plugin implements `IPaymentMethod`, a shipping plugin implements `IShippingRateComputationMethod`, and a widget plugin implements `IWidgetPlugin`.

For complete plugin lifecycle details, directory layout, and plugin group reference, see [references/plugin-architecture.md](references/plugin-architecture.md).

## Dependency Injection

nopCommerce uses its own DI bootstrap mechanism built on top of `IServiceCollection` and Autofac. Plugins register their services by implementing the `INopStartup` interface:

```csharp
public class NopStartup : INopStartup
{
    public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
    {
        services.AddScoped<IMyCustomService, MyCustomService>();
    }

    public void Configure(IApplicationBuilder application)
    {
        // Register middleware if needed
    }

    public int Order => 3000; // Higher = later in startup pipeline
}
```

The `Order` property controls when the plugin's services are registered relative to core services and other plugins. Core nopCommerce services use low order values (0-1000); plugins should use 3000+ to ensure core services are already registered.

Service lifetimes follow standard ASP.NET Core conventions: `Scoped` for per-request services (most common), `Singleton` for shared state, and `Transient` for lightweight stateless services. Most plugin services should be registered as `Scoped`.

For advanced DI patterns including Autofac integration, middleware registration, and task scheduling, see [references/dependency-injection.md](references/dependency-injection.md).

## Data Access and Entity Framework

nopCommerce uses Linq2DB as its data access layer with FluentMigrator for schema migrations. Plugins define their own entities, mappings, and migrations to extend the database schema without modifying core tables.

### Entity Definition

Plugin entities extend `BaseEntity` and define the data model:

```csharp
public class MyCustomRecord : BaseEntity
{
    public string Name { get; set; }
    public decimal Amount { get; set; }
    public int CustomerId { get; set; }
    public DateTime CreatedOnUtc { get; set; }
}
```

### Entity Builder (Schema Mapping)

Map the entity to a database table using `NopEntityBuilder<T>`:

```csharp
public class MyCustomRecordBuilder : NopEntityBuilder<MyCustomRecord>
{
    public override void MapEntity(CreateTableExpressionBuilder table)
    {
        table.WithColumn(nameof(MyCustomRecord.Name)).AsString(400).NotNullable()
             .WithColumn(nameof(MyCustomRecord.Amount)).AsDecimal(18, 4)
             .WithColumn(nameof(MyCustomRecord.CustomerId)).AsInt32();
    }
}
```

### Migrations

Use FluentMigrator to create and evolve the schema:

```csharp
[NopMigration("2024-01-15 12:00:00", "MyPlugin: create MyCustomRecord table",
    MigrationProcessType.Installation)]
public class CreateMyCustomRecordTable : AutoReversingMigration
{
    public override void Up()
    {
        Create.TableFor<MyCustomRecord>();
    }
}
```

Data access uses the `IRepository<T>` pattern for CRUD operations. Inject `IRepository<MyCustomRecord>` into services to query and manipulate plugin data.

For complete data access patterns including custom queries, Linq2DB integration, and migration strategies, see [references/data-access-and-ef.md](references/data-access-and-ef.md).

## Extension Mechanisms

nopCommerce provides several mechanisms for plugins to extend the platform beyond basic service registration.

### Event System

Subscribe to platform events using `IConsumer<T>`:

```csharp
public class OrderPlacedHandler : IConsumer<OrderPlacedEvent>
{
    public async Task HandleEventAsync(OrderPlacedEvent eventMessage)
    {
        var order = eventMessage.Order;
        // React to order placement
    }
}
```

Register the consumer in `NopStartup` and it automatically receives events published by the core system.

### View Components

Extend the admin or storefront UI using ASP.NET Core view components. Widget plugins define view components that render in specific widget zones:

```csharp
public class MyWidgetViewComponent : NopViewComponent
{
    public async Task<IViewComponentResult> InvokeAsync(string widgetZone, object additionalData)
    {
        var model = new MyWidgetModel { /* ... */ };
        return View("~/Plugins/Nop.Plugin.Widgets.MyWidget/Views/MyWidget.cshtml", model);
    }
}
```

### Admin Area Extension

Extend the admin panel with configuration pages, menu items, and custom views. Admin controllers inherit from `BasePluginController` and use Razor views with Kendo UI for data grids, forms, and dialogs.

For complete extension patterns including admin menus, sitemap providers, and JavaScript bundling, see [references/admin-extension.md](references/admin-extension.md).

## Development Setup

### Prerequisites

- **Visual Studio 2022** (Community or higher) with the ASP.NET and web development workload, or **JetBrains Rider**.
- **.NET 8 SDK** (or the version matching the target nopCommerce release).
- **Microsoft SQL Server** (Express or Developer edition) or **PostgreSQL 15+**.
- **Git** for source control.

### Getting Started

1. Clone the nopCommerce source from the official GitHub repository.
2. Open `NopCommerce.sln` in Visual Studio.
3. Create the plugin directory: `Plugins/Nop.Plugin.{Group}.{Name}/`.
4. Add a new Class Library project targeting `net8.0`.
5. Reference `Nop.Web.Framework` from the project.
6. Create `plugin.json`, the `BasePlugin` class, and `NopStartup`.
7. Build the solution -- the plugin DLL is copied to the `Nop.Web/Plugins/` directory.
8. Run `Nop.Web`, navigate to Admin > Configuration > Local Plugins, and install the plugin.

### Database Setup

On first run, nopCommerce prompts for database configuration. Select SQL Server or PostgreSQL, provide the connection string, and the installer creates all tables automatically. Plugin migrations run when the plugin is installed from the admin panel.

### Debugging

Set `Nop.Web` as the startup project and press F5 to debug. Breakpoints in plugin code work normally because the plugin DLL is loaded from the `Plugins/` directory at runtime. Enable detailed error pages by setting `ASPNETCORE_ENVIRONMENT=Development` in `launchSettings.json`.

### Testing

nopCommerce does not ship a dedicated plugin testing framework, but standard .NET testing tools apply. Use xUnit or NUnit with Moq to test plugin services by mocking `IRepository<T>` and core service interfaces. For integration testing, set up a test database and register plugin services manually using `IServiceCollection`. Test the full plugin lifecycle (install, configure, operate, uninstall) on a clean nopCommerce installation before marketplace submission.

## Anti-Patterns

Avoid these common mistakes in nopCommerce plugin development:

- **Modifying core source files** -- Never edit files in `Nop.Core`, `Nop.Services`, `Nop.Data`, or `Nop.Web` directly. Use the plugin system, events, and DI to extend functionality. Core modifications prevent upgrading to new nopCommerce versions.
- **Ignoring the plugin.json SupportedVersions field** -- Always specify the exact nopCommerce versions the plugin supports. Omitting this causes compatibility warnings and may prevent installation.
- **Using raw SQL instead of IRepository<T>** -- The repository pattern handles multi-database compatibility (SQL Server and PostgreSQL). Raw SQL queries break portability and bypass caching.
- **Registering services with wrong lifetimes** -- Database contexts and repositories are scoped. Injecting scoped services into singletons causes runtime errors. Use `Scoped` for most plugin services.
- **Skipping uninstall cleanup** -- Always drop plugin tables, remove settings, and delete locale resources in `UninstallAsync()`. Leftover data causes errors if the plugin is reinstalled or a different version is installed.
- **Hardcoding widget zone names** -- Use the constants defined in `PublicWidgetZones` and `AdminWidgetZones` classes instead of string literals. Zone names change between nopCommerce versions.
- **Blocking the startup pipeline** -- Keep `NopStartup.ConfigureServices()` lightweight. Do not perform database queries, HTTP calls, or heavy initialization during service registration.
- **Ignoring async patterns** -- nopCommerce is fully async. Calling `.Result` or `.Wait()` on async methods causes deadlocks. Always use `await` throughout the call chain.

- **Missing CopyLocalLockFileAssemblies** -- Without `<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>` in the `.csproj`, third-party NuGet dependencies are not copied to the plugin output directory, causing `FileNotFoundException` at runtime.
- **Not verifying webhook signatures** -- Payment and notification webhooks from external services must be signature-verified before processing. Skipping verification exposes the plugin to spoofed events and fraudulent state changes.

For detailed guidance on each topic, see the reference files below.

## Reference Files

- [Plugin Architecture](references/plugin-architecture.md) -- Plugin directory structure, plugin.json metadata, BasePlugin install/uninstall, plugin lifecycle, plugin groups, referencing nopCommerce libraries
- [Dependency Injection](references/dependency-injection.md) -- NopStartup class, IServiceCollection registration, service lifetimes, Autofac integration, middleware, task scheduling
- [Data Access and EF](references/data-access-and-ef.md) -- Entity classes, entity builders, FluentMigrator migrations, IRepository pattern, custom queries, Linq2DB integration
- [Admin Extension](references/admin-extension.md) -- Admin controllers and views, view components, menus and sitemap providers, configuration pages, JavaScript/CSS bundling, Kendo UI
- [Marketplace Publishing](references/marketplace-publishing.md) -- Marketplace submission, source vs DLL packaging, documentation, version compatibility, pricing, support expectations

