138 lines
7.2 KiB
Markdown
138 lines
7.2 KiB
Markdown
# Architecture
|
|
|
|
## Dependency Graph
|
|
|
|
```
|
|
AyCode.Core (net9.0, DLL refs: AyCode.Interfaces, .Entities, .Core, .Utils, + .Server variants)
|
|
↑
|
|
Mango.Nop.Core (net9.0, no nopCommerce runtime dependency)
|
|
↑
|
|
Mango.Nop.Data (net9.0) → Nop.Core, Nop.Data
|
|
↑
|
|
Mango.Nop.Services (net9.0) → Nop.Core, Nop.Data, Nop.Services, Nop.Web.Framework
|
|
```
|
|
|
|
**Rule:** Dependencies flow upward only. `Mango.Nop.Core` has zero nopCommerce runtime dependency — it uses mirror copies in `NopDependencies/`.
|
|
|
|
## Project Roles
|
|
|
|
### Mango.Nop.Core — Domain Layer
|
|
Zero nopCommerce runtime dependency. Contains:
|
|
- **DTOs** (`Dtos/`) — `ModelDtoBase<TMainEntity>` with bidirectional entity mapping (`CopyEntityValuesToDto`, `CopyDtoValuesToEntity`, `CreateMainEntity`)
|
|
- **Entities** (`Entities/`) — `MgEntityBase` (inherits `BaseEntity`, implements `IEntityInt`)
|
|
- **NopDependencies** (`NopDependencies/`) — mirror copies of nopCommerce entities (`BaseEntity`, `Customer`, `Order`, `Product`, `GenericAttribute`, enums). Allows referencing without full nopCommerce dependency chain.
|
|
- **Extensions** (`Extensions/`) — `GenericAttributeExtensions` for typed attribute access, `CollectionExtensionsNopBaseEntity` for collection operations
|
|
- **Interfaces** (`Interfaces/`) — DTO interfaces, soft-delete, foreign key markers
|
|
- **Models** (`Models/`) — Login request/response
|
|
- **Loggers** (`Loggers/`) — `ILogger` abstraction wrapping AyCode `IAcLoggerBase`
|
|
|
|
### Mango.Nop.Data — Data Access Layer
|
|
Wraps nopCommerce data infrastructure with custom base classes:
|
|
- **`MgDbTableBase<TEntity>`** — extends nopCommerce `EntityRepository<TEntity>`, adds `GetAll()`, timestamp handling (`ITimeStampCreated`, `ITimeStampModified`), event publishing
|
|
- **`MgDtoDbTableBase<TDtoEntity, TMainEntity>`** — DTO-aware repository. **Critical: Delete operations throw — must use `DeleteMainEntityById()`.** Event bridging: DTO events → main entity events
|
|
- **`MgDbContextBase`** — DB context base with `Transaction/TransactionSafe/TransactionAsync/TransactionSafeAsync` methods. TransactionSafe variants use global `SemaphoreSlim` lock
|
|
- **`MgDalBase<TDbContext>`** — Data Access Layer orchestrator with `Context`, `Name`, `MutextLock`
|
|
|
|
### Mango.Nop.Services — Service Layer
|
|
Service base classes for nopCommerce plugin development:
|
|
- **`MgBackgroundServiceBase`** — hosted background task with configurable interval, pause support, per-iteration error handling
|
|
- **`MgSessionServiceBase<TSessionItem>`** / `MgSessionItemBase` — in-memory session management via `ConcurrentDictionary`, SignalR connection tracking
|
|
- **`MgEventConsumerBase`** — nopCommerce entity event handler base (Product insert/update, CustomerRegistered, OrderPlaced, PageRendering, ProductSearch)
|
|
- **`MgLockServiceBase`** — `SemaphoreSlim(1)` lock wrapper
|
|
- **`NopLogWriter`** — logging bridge: AyCode log levels → nopCommerce `Log` table via direct DB insert with `TransactionScope(Suppress)`
|
|
|
|
## NopDependencies Pattern
|
|
|
|
`Mango.Nop.Core/NopDependencies/` contains mirror copies of nopCommerce entity classes with the **same namespace** as the original nopCommerce types:
|
|
|
|
```csharp
|
|
// In NopDependencies/BaseEntity.cs — same namespace as nopCommerce
|
|
namespace Nop.Core;
|
|
public abstract partial class BaseEntity : IBaseEntity
|
|
{
|
|
public int Id { get; set; }
|
|
}
|
|
```
|
|
|
|
This allows `Mango.Nop.Core` to be referenced by projects that don't have a direct nopCommerce dependency (e.g., Blazor/MAUI clients), while maintaining type compatibility with the real nopCommerce entities at the server level.
|
|
|
|
**Files in NopDependencies:**
|
|
- `BaseEntity.cs` + `IBaseEntity` — root entity base (`Nop.Core`)
|
|
- `Catalogs/` — `Customer`, `CustomerRole`, `Order`, `OrderItem`, `OrderNote`, `Product`, `GenericAttribute`, `StockQuantityHistory`, `DiscountMapping`, `DiscountProductMapping`
|
|
- Enums — `OrderStatus`, `PaymentStatus`, `ShippingStatus`, `ProductType`, `ManageInventoryMethod`, `BackorderMode`, `LowStockActivity`, `GiftCardType`, `RentalPricePeriod`, `RecurringProductCyclePeriod`, `DownloadActivationType`, `TaxDisplayType`, `VatNumberStatus`
|
|
- Interfaces — `ISoftDeletedEntity`, `ILocalizedEntity`, `ISlugSupported`, `IAclSupported`, `IStoreMappingSupported`, `IDiscountSupported`
|
|
|
|
## DTO Mapping Strategies
|
|
|
|
Two patterns coexist:
|
|
|
|
### Strategy 1: `ModelDtoBase<T>` (simple DTOs)
|
|
Used by: `CustomerDto`, `MgGenericAttributeDto`
|
|
```
|
|
ModelDtoBase → ModelDtoBase<Customer> → CustomerDto
|
|
```
|
|
- Manual `CopyEntityValuesToDto`/`CopyDtoValuesToEntity` overrides
|
|
- No LinqToDB associations
|
|
|
|
### Strategy 2: `MgEntityBase` + `IModelDtoBase<T>` (complex DTOs)
|
|
Used by: `MgOrderDto`, `MgOrderItemDto`, `MgStockQuantityHistoryDto`
|
|
```
|
|
BaseEntity → MgEntityBase → MgOrderDto<TOrderItemDto, TProductDto> : IModelDtoBase<Order>
|
|
```
|
|
- Uses `PropertyHelper.CopyPublicValueTypeProperties()` for bulk copy
|
|
- LinqToDB `[Association]` navigation properties
|
|
- Generic type parameters for child DTOs
|
|
|
|
### Strategy 3: Entity inheritance (MgProductDto)
|
|
```
|
|
BaseEntity → MgEntityBase → MgProductDto : IMgProductDto
|
|
```
|
|
- No `IModelDtoBase<Product>` (entity mapping methods are commented out)
|
|
- Direct property declarations mirroring `Product` fields
|
|
|
|
## Transaction Pattern
|
|
|
|
`MgDbContextBase` provides 4 transaction methods:
|
|
|
|
| Method | Lock | Async |
|
|
|---|---|---|
|
|
| `Transaction(callback)` | No | No |
|
|
| `TransactionSafe(callback)` | `SemaphoreSlim` | No |
|
|
| `TransactionAsync(callback)` | No | Yes (thread pool) |
|
|
| `TransactionSafeAsync(callback)` | `SemaphoreSlim` | Yes (thread pool) |
|
|
|
|
**Callback contract:** `Func<TransactionScope, (Task<)bool(>)>` — return `true` to commit, `false` to rollback.
|
|
**Isolation level:** `ReadCommitted`
|
|
**Error handling:** Catches exceptions, logs, returns `false` (unless `throwException = true`)
|
|
|
|
## Logging Architecture
|
|
|
|
Base logging infrastructure (`IAcLoggerBase`, `IAcLogWriterBase`, `AcLoggerBase`, `AcLogItemWriterBase`, `AcLogItem`) is defined in AyCode.Core — see `AyCode.Core/docs/LOGGING.md` for base types, log levels, and writer contracts.
|
|
|
|
This layer provides the nopCommerce-specific bridge:
|
|
|
|
```
|
|
Application code → Mango.Nop.Core.Loggers.ILogger (extends IAcLoggerBase)
|
|
→ Logger<TCategory> (extends AcLoggerBase, delegates to IAcLogWriterBase[])
|
|
→ NopLogWriter (in Services, extends AcLogItemWriterBase<AcLogItem>) → Nop Log table (direct SQL insert)
|
|
→ [Other AyCode log writers: console, file, SignalR, etc. — see AyCode.Core/docs/LOGGING.md]
|
|
```
|
|
|
|
**Important:** `MgBackgroundServiceBase` uses nopCommerce's `Nop.Services.Logging.ILogger` directly (not the Mango wrapper). Other services use `Mango.Nop.Core.Loggers.ILogger`.
|
|
|
|
## Reference Modes
|
|
|
|
```
|
|
Mango.Nop Libraries
|
|
┌──────────────────────┐
|
|
│ Core Data Services │
|
|
└──┬──────┬──────┬─────┘
|
|
│ │ │
|
|
┌───────────────┤ │ │
|
|
│ (DLL, Core │ │ │
|
|
│ only) │ │ │
|
|
▼ ▼ ▼ ▼
|
|
Types-only clients Full-stack nopCommerce
|
|
(Blazor/MAUI/etc.) plugins (server-side)
|
|
```
|