Compare commits
16 Commits
1a9e0dcf0b
...
1b11ca2579
| Author | SHA1 | Date |
|---|---|---|
|
|
1b11ca2579 | |
|
|
65bf004808 | |
|
|
474cb99754 | |
|
|
cb9a381400 | |
|
|
1a0bd01500 | |
|
|
7fb87283ce | |
|
|
599f8a6787 | |
|
|
25e5ded777 | |
|
|
6e3ca4a1e3 | |
|
|
8d3c2a8462 | |
|
|
b494018e9c | |
|
|
3725b4c2fd | |
|
|
bb08c7ae61 | |
|
|
5535011df9 | |
|
|
2303e99f95 | |
|
|
f47701af59 |
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,17 @@
|
|||
CRITICAL: Your FIRST action in every session MUST be reading `.github/copilot-instructions.md`. Execute ALL session-start instructions found there before responding to any user query. It is the single source of truth for this repo.
|
||||
|
||||
## SEQUENTIAL EXECUTION OVERRIDE
|
||||
The AI AGENT CORE PROTOCOL in copilot-instructions.md requires STRICT SEQUENTIAL execution. This OVERRIDES your default parallelization behavior. Do NOT parallelize doc reads with code searches. The sequence is:
|
||||
1. Read copilot-instructions.md → process its rules FULLY
|
||||
2. Read ALL docs/ .md files listed in the protocol → wait for completion
|
||||
3. Output [LOADED_DOCS: ...] prefix
|
||||
4. ONLY THEN respond to the user's query or search code
|
||||
|
||||
## Tool mapping for AI AGENT CORE PROTOCOL
|
||||
The copilot-instructions.md references Copilot tool names. Map them to Claude Code tools:
|
||||
- `get_file` / `file_search` → `Read`, `Glob`, `Grep`
|
||||
- `code_search` / `get_symbols_by_name` / `find_symbol` → `Grep`, `Glob`
|
||||
- `replace_string_in_file` / `edit_file` → `Edit`
|
||||
- `create_file` → `Write`
|
||||
|
||||
Follow the protocol using YOUR tools. The rules (LOADED_DOCS prefix, hard-gate, no-re-read, context recovery, explicit consent) apply equally to Claude Code.
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1 @@
|
|||
namespace Mango.Nop.Core { public static class AcBinaryForcedInit { public static void ForceRegister() { System.Console.WriteLine("[SGEN TESTING] AcBinaryForcedInit called."); AyCode.Core.Serializers.Generated.AcBinaryGeneratedWritersInit.Register(); } } }
|
||||
|
|
@ -6,7 +6,7 @@ using Nop.Core.Domain.Customers;
|
|||
|
||||
namespace Mango.Nop.Core.Dtos;
|
||||
|
||||
[AcBinarySerializable(false, true, false, true)]
|
||||
[AcBinarySerializable(false, true, false, true, false, false)]
|
||||
[LinqToDB.Mapping.Table(Name = nameof(Customer))]
|
||||
[System.ComponentModel.DataAnnotations.Schema.Table(nameof(Customer))]
|
||||
[ToonDescription($"Data transfer object for {nameof(Customer)}", TypeRelation = ToonTypeRelation.DtoOf, RelatedTypes = [typeof(Customer)])]
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
<Nullable>enable</Nullable>
|
||||
<BaseOutputPath>bin\FruitBank</BaseOutputPath>
|
||||
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<CopyRefAssembliesToPublishDirectory>true</CopyRefAssembliesToPublishDirectory>
|
||||
</PropertyGroup>
|
||||
|
|
@ -40,9 +41,20 @@
|
|||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\..\..\Aycode\Source\AyCode.Core\AyCode.Core.Serializers.SourceGenerator\AyCode.Core.Serializers.SourceGenerator.csproj"
|
||||
OutputItemType="Analyzer"
|
||||
ReferenceOutputAssembly="false" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="ExtendedFactories\" />
|
||||
<Folder Include="ExtendedModels\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="docs\**\*.md" />
|
||||
<None Include="**\README.md" Exclude="$(DefaultItemExcludes);docs\**" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace Nop.Core.Domain.Customers;
|
|||
/// <summary>
|
||||
/// Represents a customer
|
||||
/// </summary>
|
||||
[AcBinarySerializable(false, true, false, true)]
|
||||
[AcBinarySerializable(false, true, false, true, false, false)]
|
||||
[ToonDescription("NopCommerce customer entity")]
|
||||
public partial class Customer : BaseEntity, ISoftDeletedEntity
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace Nop.Core.Domain.Customers;
|
|||
/// <summary>
|
||||
/// Represents a customer role
|
||||
/// </summary>
|
||||
[AcBinarySerializable(false, true, false, true)]
|
||||
[AcBinarySerializable(false, true, false, true, false, false)]
|
||||
public partial class CustomerRole : BaseEntity
|
||||
{
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ namespace Nop.Core.Domain.Discounts;
|
|||
/// <summary>
|
||||
/// Represents a discount-product mapping class
|
||||
/// </summary>
|
||||
[AcBinarySerializable(false, true, false, true)]
|
||||
// SGen incompatible: DiscountMapping.Id is readonly (new int Id { get; }) — generated reader cannot set it (CS0200)
|
||||
//[AcBinarySerializable(false, true, false, true, false)]
|
||||
public partial class DiscountProductMapping : DiscountMapping
|
||||
{
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ namespace Nop.Core.Domain.Common;
|
|||
/// <summary>
|
||||
/// Represents a generic attribute
|
||||
/// </summary>
|
||||
[AcBinarySerializable(false, true, false, true)]
|
||||
[AcBinarySerializable(false, true, false, true, false, false)]
|
||||
[ToonDescription("NopCommerce generic attribute for key-value storage", Purpose = "A flexible key-value store used to extend entities with custom business logic data without changing the database schema")]
|
||||
public partial class GenericAttribute : BaseEntity
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ namespace Nop.Core.Domain.Orders;
|
|||
/// <summary>
|
||||
/// Represents an order
|
||||
/// </summary>
|
||||
[AcBinarySerializable(false, true, false, true)]
|
||||
[AcBinarySerializable(false, true, false, true, false, false)]
|
||||
[ToonDescription("NopCommerce order entity with payment and shipping")]
|
||||
public partial class Order : BaseEntity, ISoftDeletedEntity
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ using AyCode.Core.Serializers.Toons;
|
|||
/// <summary>
|
||||
/// Represents an order item
|
||||
/// </summary>
|
||||
[AcBinarySerializable(false, true, false, true)]
|
||||
[AcBinarySerializable(false, true, false, true, false, false)]
|
||||
[ToonDescription("NopCommerce order item entity")]
|
||||
public partial class OrderItem : BaseEntity
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ namespace Nop.Core.Domain.Orders;
|
|||
/// <summary>
|
||||
/// Represents an order note
|
||||
/// </summary>
|
||||
[AcBinarySerializable(false, true, false, true)]
|
||||
[AcBinarySerializable(false, true, false, true, false, false)]
|
||||
[ToonDescription("NopCommerce order note entity")]
|
||||
public partial class OrderNote : BaseEntity
|
||||
{
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ namespace Nop.Core.Domain.Catalog;
|
|||
/// <summary>
|
||||
/// Represents a product
|
||||
/// </summary>
|
||||
[AcBinarySerializable(false, true, false, true)]
|
||||
[AcBinarySerializable(false, true, false, true, false, false)]
|
||||
[ToonDescription("Core nopCommerce product entity with catalog, pricing, and inventory management")]
|
||||
public partial class Product : BaseEntity, ILocalizedEntity, ISlugSupported, IAclSupported, IStoreMappingSupported, IDiscountSupported<DiscountProductMapping>, ISoftDeletedEntity
|
||||
{
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public interface IMgStockQuantityHistory
|
|||
/// <summary>
|
||||
/// Represents a stock quantity change entry
|
||||
/// </summary>
|
||||
[AcBinarySerializable(false, true, false, true)]
|
||||
[AcBinarySerializable(false, true, false, true, false, false)]
|
||||
[Table(Name = nameof(StockQuantityHistory))]
|
||||
[ToonDescription("NopCommerce stock movement log", Purpose = "Audit trail for physical and logical stock movements")]
|
||||
public partial class StockQuantityHistory : BaseEntity, IMgStockQuantityHistory
|
||||
|
|
|
|||
|
|
@ -0,0 +1,105 @@
|
|||
# Mango.Nop.Core
|
||||
|
||||
@project {
|
||||
type = "framework"
|
||||
own-dep-projects = [
|
||||
"AyCode.Core, AyCode.Core.Server, AyCode.Entities, AyCode.Entities.Server, AyCode.Interfaces, AyCode.Interfaces.Server, AyCode.Utils (in AyCode.Core repo)"
|
||||
]
|
||||
}
|
||||
|
||||
Shared domain library containing entities, DTOs, interfaces, and nopCommerce entity mirrors. **net9.0**. Zero nopCommerce runtime dependency.
|
||||
|
||||
## Documentation
|
||||
|
||||
| Document | Topic |
|
||||
|---|---|
|
||||
| `DTOS.md` | DTO system — two mapping strategies, all DTO types, GenericAttribute typed access |
|
||||
| `NOP_DEPENDENCIES.md` | NopDependencies pattern — mirror copies, namespace rules, file list |
|
||||
|
||||
## Folder Structure
|
||||
|
||||
| Folder | Purpose |
|
||||
|---|---|
|
||||
| `Dtos/` | DTO classes shared across consumers |
|
||||
| `Entities/` | Custom domain entities |
|
||||
| `Extensions/` | Extension methods for `BaseEntity` collections and `GenericAttribute` |
|
||||
| `Interfaces/` | DTO interfaces, soft-delete, foreign key markers |
|
||||
| `Loggers/` | `ILogger` / `Logger` — logging abstraction wrapping AyCode logger |
|
||||
| `Models/` | Login request/response models |
|
||||
| `NopDependencies/` | Mirror copies of nopCommerce entity classes (same namespaces as originals) |
|
||||
| `Services/` | `IMgLockService` interface |
|
||||
| `Utils/` | `CommonHelper2` — email validation, type conversion utilities |
|
||||
|
||||
## Entity Hierarchy
|
||||
|
||||
```
|
||||
Nop.Core.BaseEntity (NopDependencies/, implements IBaseEntity)
|
||||
+-- MgEntityBase (Entities/, implements IEntityInt from AyCode)
|
||||
+-- MgOrderDto<TOrderItemDto, TProductDto>
|
||||
+-- MgOrderItemDto<TProductDto>
|
||||
+-- MgProductDto
|
||||
+-- MgStockQuantityHistoryDto<TProductDto>
|
||||
+-- MgStockTaking<TStockTakingItem>
|
||||
+-- MgStockTakingItem<TStockTaking, TProduct>
|
||||
```
|
||||
|
||||
## Key Types (not in docs/)
|
||||
|
||||
### Entities
|
||||
|
||||
| Type | Key features |
|
||||
|---|---|
|
||||
| `MgEntityBase` | Inherits `BaseEntity`, implements `IEntityInt`. `ToString()` -> `"{TypeName}; Id: {Id}"` |
|
||||
| `MgStockTaking<TStockTakingItem>` | `StartDateTime`, `IsClosed`, `List<TStockTakingItem>` navigation. Implements `ITimeStampInfo` |
|
||||
| `MgStockTakingItem<TStockTaking, TProduct>` | `StockTakingId`, `ProductId`, `IsMeasured`, stock quantities. Navigations to parent and product |
|
||||
|
||||
### Extensions
|
||||
|
||||
| Method | Purpose |
|
||||
|---|---|
|
||||
| `UpdateBaseEntityCollection` | Add/update/remove entities in a list by Id match |
|
||||
|
||||
### Loggers
|
||||
|
||||
Extends AyCode logging infrastructure — for base types see `AyCode.Core/AyCode.Core/docs/LOGGING/README.md`.
|
||||
|
||||
| Type | Inherits | Purpose |
|
||||
|---|---|---|
|
||||
| `ILogger` | `IAcLoggerBase` | Mango-level logger interface |
|
||||
| `ILogger<TCategory>` | `ILogger` | Generic category logger interface |
|
||||
| `Logger` | `AcLoggerBase` | Logger implementation with `IAcLogWriterBase[]` writers |
|
||||
| `Logger<TCategory>` | `Logger` | Typed logger — category name from `typeof(TCategory).Name` |
|
||||
|
||||
### Models
|
||||
|
||||
| Type | Purpose |
|
||||
|---|---|
|
||||
| `MgLoginModelRequest` | `Email` + `Password` for SignalR/API login |
|
||||
| `MgLoginModelResponse` | `CustomerDto?` + `ErrorMessage`. Computed `IsSuccesLogin` |
|
||||
|
||||
### Other
|
||||
|
||||
| Type | Purpose |
|
||||
|---|---|
|
||||
| `NopCommonConst` | Abstract const class inheriting `AcConst` (placeholder) |
|
||||
| `CommonHelper2` | Email validation, IP validation, type conversion (`To<T>`), string utilities |
|
||||
|
||||
## Dependencies
|
||||
|
||||
- `linq2db` — data access, `[Association]` / `[Table]` attributes
|
||||
- `Microsoft.AspNetCore.Mvc.NewtonsoftJson` — JSON serialization
|
||||
- Binary serialization: `AcBinarySerializer` (see `AyCode.Core/AyCode.Core/docs/BINARY/BINARY_FORMAT.md`). SignalR transport: `AcSignalR` (see `AyCode.Core/AyCode.Services/docs/SIGNALR/README.md`).
|
||||
- `AyCode.Core.Serializers.SourceGenerator` (ProjectReference, `OutputItemType="Analyzer"`) — compile-time binary serializer. See [`AyCode.Core/docs/BINARY_SOURCE_GEN.md`](../../../../../../Aycode/Source/AyCode.Core/AyCode.Core/docs/BINARY_SOURCE_GEN.md)
|
||||
- AyCode DLL references: `AyCode.Interfaces`, `AyCode.Core`, `AyCode.Utils`, `AyCode.Entities` (types only, no runtime nopCommerce dependency)
|
||||
|
||||
## AcBinary Source Generator (SGen)
|
||||
|
||||
9 types annotated with `[AcBinarySerializable]`. For general SGen docs see [`AyCode.Core/docs/BINARY_SOURCE_GEN.md`](../../../../../../Aycode/Source/AyCode.Core/AyCode.Core/docs/BINARY_SOURCE_GEN.md).
|
||||
|
||||
Requires `InternalsVisibleTo("Mango.Nop.Core")` in `AyCode.Core/Properties/AssemblyInfo.cs`.
|
||||
|
||||
### Excluded types
|
||||
|
||||
| Type | Reason |
|
||||
|---|---|
|
||||
| `DiscountProductMapping` | Base `DiscountMapping` hides `BaseEntity.Id` with readonly `new int Id { get; }` → CS0200. Uses compiled-expression fallback. |
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
# Architecture
|
||||
|
||||
## Framework vs. Consumer Boundary
|
||||
|
||||
This solution is **Layer 2 — Domain framework** (NopCommerce-plugin base). Built on Layer 0 (AyCode.Core), consumed by Layer 3 (specific plugin apps, plural and unknown). Full doctrine: AyCode.Core's `docs/ARCHITECTURE.md#framework-vs-consumer-boundary`.
|
||||
|
||||
### Layer position
|
||||
|
||||
```
|
||||
Layer 0 — AyCode.Core universal primitives (serializers, logging, entities)
|
||||
Layer 2 — Mango.Nop.Core this solution — NopCommerce-plugin domain framework
|
||||
Layer 3 — Consumer plugin apps specific plugin projects with business logic
|
||||
```
|
||||
|
||||
### Nop-plugin-framework-specific notes
|
||||
|
||||
- **`NopDependencies/`** mirrors NopCommerce entity classes under the original Nop namespaces — no runtime Nop dependency, compile-time type parity only
|
||||
- **DTOs** use type parameters for consumer entity types (e.g. `MgOrderDto<TOrderItemDto, TProductDto>`) — concrete types are provided by plugin projects
|
||||
- **Entity hierarchy**: `Nop.Core.BaseEntity` (mirrored) → `MgEntityBase` → generic DTOs/entities parameterized for consumers
|
||||
- **`Logger` / `ILogger`** extend AyCode logging (`AcLoggerBase`) — plugin projects may subclass again if business-specific writers are needed
|
||||
- **Zero runtime Nop dependency** — plugin apps bring their own Nop runtime
|
||||
|
||||
### What belongs here vs. in a plugin
|
||||
|
||||
**Yes, framework:**
|
||||
- NopCommerce entity mirrors (for cross-plugin type sharing)
|
||||
- Generic DTOs with type parameters
|
||||
- Shared interfaces and extensions for NopCommerce domain entities
|
||||
- Logger base with AyCode integration
|
||||
|
||||
**No, plugin only:**
|
||||
- Plugin-specific business logic
|
||||
- Plugin-named types (`XxxPlugin`, `XxxService` where Xxx is a specific product)
|
||||
- Hardcoded plugin configuration, tenant, or product IDs
|
||||
|
||||
## Related Documents
|
||||
|
||||
| Topic | Document |
|
||||
|---|---|
|
||||
| Framework-first doctrine (full) | `../../../../../../../Aycode/Source/AyCode.Core/docs/ARCHITECTURE.md#framework-vs-consumer-boundary` |
|
||||
| Placement rules, anti-patterns | `CONVENTIONS.md#framework-first-placement` |
|
||||
| DTO system and GenericAttribute typed access | `DTOS.md` |
|
||||
| NopDependencies mirror pattern | `NOP_DEPENDENCIES.md` |
|
||||
| Folder structure and key types index | `../README.md` |
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
# Conventions
|
||||
|
||||
For core framework conventions (Ac prefix, naming patterns, Session/Transaction, etc.) see AyCode.Core's `docs/CONVENTIONS.md`.
|
||||
|
||||
## Framework-First Placement
|
||||
|
||||
Follow the doctrine in AyCode.Core's `docs/CONVENTIONS.md#framework-first-placement`. Same verdict table and hard rules apply.
|
||||
|
||||
**Nop-plugin-framework-specific additions:**
|
||||
- `NopDependencies/` mirror classes stay in their original Nop namespaces — don't rename, don't add plugin-specific fields
|
||||
- DTOs parameterize via type arguments, not concrete plugin types
|
||||
- Any plugin-specific business logic belongs in the plugin project, not here
|
||||
- Adding a new shared DTO: ensure it is useful for 2+ plugin projects (otherwise keep in the single plugin)
|
||||
|
||||
## Naming
|
||||
|
||||
- **`Mg` prefix**: for Mango-framework-level types (e.g. `MgEntityBase`, `MgOrderDto`, `MgProductDto`)
|
||||
- **`IMg` prefix**: for Mango-framework-level interfaces (e.g. `IMgModelDtoBase`, `IMgSoftRemoveEntity`)
|
||||
- **No prefix**: for NopCommerce entity mirrors in `NopDependencies/` — they stay in Nop namespace, same name as upstream
|
||||
|
||||
## XML Documentation
|
||||
|
||||
`<summary>` — brief, developer-facing, readable in VS IntelliSense tooltip. NO implementation details, NO wire-format / byte-level / perf specifics — those live in `docs/TOPIC/*.md`. Add `<example>` only when usage is non-obvious; otherwise omit.
|
||||
|
||||
## See Also
|
||||
|
||||
- Core framework naming (`Ac` / `IAc` prefixes), patterns, serialization conventions: AyCode.Core's `docs/CONVENTIONS.md`
|
||||
- Framework-first verdict table (full): AyCode.Core's `docs/CONVENTIONS.md#framework-first-placement`
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
# DTO System
|
||||
|
||||
> Part of `Mango.Nop.Core`. See `Mango.Nop.Core/README.md` for project overview.
|
||||
|
||||
## Two Mapping Strategies
|
||||
|
||||
### Strategy 1: `ModelDtoBase<T>` (simple DTOs)
|
||||
|
||||
Used by: `CustomerDto`, `MgGenericAttributeDto`
|
||||
|
||||
```
|
||||
ModelDtoBase → ModelDtoBase<Customer> → CustomerDto
|
||||
```
|
||||
|
||||
- Manual `CopyEntityValuesToDto`/`CopyDtoValuesToEntity` overrides
|
||||
- `CreateMainEntity()` uses `Activator.CreateInstance<T>()`
|
||||
- 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 value-type 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
|
||||
|
||||
## DTO Types
|
||||
|
||||
| Type | Generic params | Maps to entity | Key features |
|
||||
|---|---|---|---|
|
||||
| `ModelDtoBase` | — | — | Abstract base, `int Id` only |
|
||||
| `ModelDtoBase<TMainEntity>` | `TMainEntity : BaseEntity` | `TMainEntity` | `CreateMainEntity()`, `CopyEntityValuesToDto()`, `CopyDtoValuesToEntity()` |
|
||||
| `MgOrderDto<TOrderItemDto, TProductDto>` | `TOrderItemDto : IMgOrderItemDto<TProductDto>`, `TProductDto : IMgProductDto` | `Order` | Has `Customer`, `List<TOrderItemDto>`, `List<OrderNote>` navigations. Enum wrappers: `OrderStatus`, `ShippingStatus`, `PaymentStatus` |
|
||||
| `MgOrderItemDto<TProductDto>` | `TProductDto : IMgProductDto` | `OrderItem` | Has `TProductDto?` navigation. Computed `ProductName` property |
|
||||
| `MgProductDto` | — | *(commented out)* | Base product DTO. Name, Price, StockQuantity, dimensions. No entity mapping methods (currently commented out) |
|
||||
| `MgGenericAttributeDto` | — | `GenericAttribute` | Inherits `GenericAttribute` directly (not `ModelDtoBase`). Full bidirectional mapping |
|
||||
| `MgStockQuantityHistoryDto<TProductDto>` | `TProductDto : IMgProductDto` | `StockQuantityHistory` | Has `TProductDto` navigation. Mapping methods `NotImplementedException` (stub) |
|
||||
| `CustomerDto` | — | `Customer` | `Username`, `Email`, `FirstName`, `LastName`, `FullName` computed. Uses `[AcBinarySerializable]` and LinqToDB `[Table]` |
|
||||
|
||||
## DTO Interfaces
|
||||
|
||||
| Interface | Extends | Purpose |
|
||||
|---|---|---|
|
||||
| `IModelDtoBase` | `IEntityInt`, `IModelDtoBaseEmpty` | Marker for all DTOs with `int Id` |
|
||||
| `IModelDtoBase<TMainEntity>` | `IModelDtoBase` | Bidirectional mapping contract: `CreateMainEntity()`, `CopyDtoValuesToEntity()`, `CopyEntityValuesToDto()` |
|
||||
| `IMgOrderDto<TOrderItemDto, TProductDto>` | `IEntityInt`, `ISoftDeletedEntity` | Order DTO contract with navigation properties and initialization methods |
|
||||
| `IMgOrderItemDto<TProductDto>` | `IEntityInt` | Order item DTO contract with product navigation |
|
||||
| `IMgProductDto` | `IEntityInt`, `ILocalizedEntity`, `ISlugSupported`, `IAclSupported`, `IStoreMappingSupported`, `ISoftDeletedEntity` | Product DTO contract |
|
||||
|
||||
## GenericAttribute Typed Access
|
||||
|
||||
`GenericAttributeExtensions` provides typed access to nopCommerce's polymorphic key-value store:
|
||||
|
||||
| Method | Signature | Purpose |
|
||||
|---|---|---|
|
||||
| `GetValueOrNull<TValue>` | `(IEnumerable<GenericAttribute>, string key) -> TValue?` | Get typed value, returns null if not found |
|
||||
| `GetValueOrDefault<TValue>` | `(IEnumerable<GenericAttribute>, string key, TValue default) -> TValue` | Same with default fallback |
|
||||
| `TryGetValue<TValue>` | `(IEnumerable<GenericAttribute>, string key, out TValue?) -> bool` | Try-pattern for GA value |
|
||||
| `AddNewGenericAttribute` | `(ICollection<GenericAttribute>, ...) -> GenericAttribute` | Create and add new GA with UTC timestamp |
|
||||
|
||||
**Rule:** Always use these extension methods — never parse `GenericAttribute.Value` strings manually.
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
# NopDependencies Pattern
|
||||
|
||||
> Part of `Mango.Nop.Core`. See `Mango.Nop.Core/README.md` for project overview.
|
||||
|
||||
## Why
|
||||
|
||||
`Mango.Nop.Core` has **zero nopCommerce runtime dependency**. This allows it to be referenced by projects that don't have the full nopCommerce stack (e.g. Blazor/MAUI clients that only need DTOs and interfaces).
|
||||
|
||||
To achieve this, `NopDependencies/` contains **mirror copies** of nopCommerce entity classes with the **same namespace** as the originals:
|
||||
|
||||
```csharp
|
||||
// In NopDependencies/BaseEntity.cs — same namespace as nopCommerce
|
||||
namespace Nop.Core;
|
||||
public abstract partial class BaseEntity : IBaseEntity
|
||||
{
|
||||
public int Id { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
At compile time, projects referencing only `Mango.Nop.Core` get these mirror types. Projects with the full nopCommerce stack get the real types — they are type-compatible because they share the same namespace and shape.
|
||||
|
||||
## Rules
|
||||
|
||||
- **DO NOT modify** files in `NopDependencies/` unless the nopCommerce version changes
|
||||
- **DO NOT change namespaces** — they must match the original nopCommerce types exactly
|
||||
- All mirror classes are `partial` — they can be extended but should not be modified directly
|
||||
|
||||
## File List
|
||||
|
||||
| File | Namespace | Type |
|
||||
|---|---|---|
|
||||
| `BaseEntity.cs` | `Nop.Core` | `BaseEntity` (abstract, `IBaseEntity`) + `IBaseEntity` interface |
|
||||
| `Catalogs/Customer.cs` | `Nop.Core.Domain.Customers` | `Customer` |
|
||||
| `Catalogs/CustomerRole.cs` | `Nop.Core.Domain.Customers` | `CustomerRole` |
|
||||
| `Catalogs/Order.cs` | `Nop.Core.Domain.Orders` | `Order` |
|
||||
| `Catalogs/OrderItem.cs` | `Nop.Core.Domain.Orders` | `OrderItem` |
|
||||
| `Catalogs/OrderNote.cs` | `Nop.Core.Domain.Orders` | `OrderNote` |
|
||||
| `Catalogs/Product.cs` | `Nop.Core.Domain.Catalog` | `Product` |
|
||||
| `Catalogs/GenericAttribute.cs` | `Nop.Core.Domain.Common` | `GenericAttribute` |
|
||||
| `Catalogs/StockQuantityHistory.cs` | `Nop.Core.Domain.Catalog` | `StockQuantityHistory` |
|
||||
| `Catalogs/DiscountMapping.cs` | `Nop.Core.Domain.Catalog` | `DiscountMapping` |
|
||||
| `Catalogs/DiscountProductMapping.cs` | `Nop.Core.Domain.Catalog` | `DiscountProductMapping` |
|
||||
|
||||
**Enums:** `OrderStatus`, `PaymentStatus`, `ShippingStatus`, `ProductType`, `ManageInventoryMethod`, `BackorderMode`, `LowStockActivity`, `GiftCardType`, `RentalPricePeriod`, `RecurringProductCyclePeriod`, `DownloadActivationType`, `TaxDisplayType`, `VatNumberStatus`
|
||||
|
||||
**Interfaces:** `ISoftDeletedEntity`, `ILocalizedEntity`, `ISlugSupported`, `IAclSupported`, `IStoreMappingSupported`, `IDiscountSupported`
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# Mango.Nop.Core documentation
|
||||
|
||||
Topic documentation for the `Mango.Nop.Core` project (Layer 2 framework — NopCommerce-adjacent base types).
|
||||
|
||||
## Reference docs (flat)
|
||||
|
||||
- [`ARCHITECTURE.md`](ARCHITECTURE.md) — Project architecture
|
||||
- [`CONVENTIONS.md`](CONVENTIONS.md) — Project-specific conventions
|
||||
- [`DTOS.md`](DTOS.md) — DTO system, mapping strategies
|
||||
- [`NOP_DEPENDENCIES.md`](NOP_DEPENDENCIES.md) — NopCommerce entity mirror pattern
|
||||
|
||||
## Navigation
|
||||
|
||||
Per the AI Agent Core Protocol (folder navigation rule), start from this README when browsing `docs/`. All docs at this level are single-file reference; topic folders (e.g., LOGGING/) exist only at sub-projects that host a variant (see `../Mango.Nop.Services/docs/LOGGING/`).
|
||||
|
||||
## See also
|
||||
|
||||
- **Repo-level conventions**: `../../docs/CONVENTIONS.md`
|
||||
- **Base framework**: `../../../../../Aycode/Source/AyCode.Core/` docs
|
||||
|
|
@ -44,4 +44,10 @@
|
|||
<HintPath>..\..\..\..\..\..\Aycode\Source\AyCode.Core\AyCode.Services.Server\bin\FruitBank\$(Configuration)\net9.0\AyCode.Utils.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="docs\**\*.md" />
|
||||
<None Include="**\README.md" Exclude="$(DefaultItemExcludes);docs\**" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
# Mango.Nop.Data
|
||||
|
||||
@project {
|
||||
type = "framework"
|
||||
own-dep-projects = [
|
||||
"AyCode.Core, AyCode.Core.Server, AyCode.Entities, AyCode.Entities.Server, AyCode.Interfaces, AyCode.Interfaces.Server, AyCode.Utils (in AyCode.Core repo)"
|
||||
]
|
||||
}
|
||||
|
||||
Data access layer with repository base classes and DB context abstractions. **net9.0**.
|
||||
|
||||
## Documentation
|
||||
|
||||
| Document | Topic |
|
||||
|---|---|
|
||||
| `REPOSITORIES.md` | MgDbTableBase, MgDtoDbTableBase — CRUD hooks, timestamps, delete rules, event bridging |
|
||||
| `TRANSACTIONS.md` | MgDbContextBase — 4 transaction methods, lock strategy, callback contract |
|
||||
|
||||
## Folder Structure
|
||||
|
||||
| Folder | Purpose |
|
||||
|---|---|
|
||||
| `Interfaces/` | Repository interfaces: `IMgDalBase`, `IMgDbContextBase`, `IMgDbTableBase` |
|
||||
| `Repositories/` | Repository base implementations: `MgDalBase`, `MgDbContextBase`, `MgDbTableBase`, `MgDtoDbTableBase` |
|
||||
|
||||
## Inheritance Chains
|
||||
|
||||
### Repository hierarchy
|
||||
```
|
||||
nopCommerce EntityRepository<TEntity> (Nop.Data)
|
||||
+-- MgDbTableBase<TEntity>
|
||||
+-- MgDtoDbTableBase<TDtoEntity, TMainEntity>
|
||||
```
|
||||
|
||||
### Context hierarchy
|
||||
```
|
||||
MgDbContextBase (abstract, implements IMgDbContextBase)
|
||||
+-- [Consumer DbContexts in plugins]
|
||||
```
|
||||
|
||||
### DAL hierarchy
|
||||
```
|
||||
MgDalBase<TDbContext> (implements IMgDalBase<TDbContext>)
|
||||
+-- [Consumer DALs in plugins]
|
||||
```
|
||||
|
||||
## Interfaces
|
||||
|
||||
| Interface | Purpose |
|
||||
|---|---|
|
||||
| `IMgDbTableBase` | Marker interface for repository classes |
|
||||
| `IMgDbContextBase` | Contract: `Logger`, `DataProvider`, `Orders`, `Products`, 4 transaction methods |
|
||||
| `IMgDalBase` | `Name` property |
|
||||
| `IMgDalBase<TDbContext>` | `Context`, `MutextLock` — typed access to DB context |
|
||||
|
||||
## Dependencies
|
||||
|
||||
- `Mango.Nop.Core` (ProjectReference)
|
||||
- `Nop.Core`, `Nop.Data` (nopCommerce ProjectReferences)
|
||||
- `Microsoft.AspNetCore.Mvc.NewtonsoftJson`
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# Mango.Nop.Data documentation
|
||||
|
||||
Topic documentation for the `Mango.Nop.Data` project (Layer 2, data access layer).
|
||||
|
||||
## Reference docs (flat)
|
||||
|
||||
- [`REPOSITORIES.md`](REPOSITORIES.md) — Repository pattern usage
|
||||
- [`TRANSACTIONS.md`](TRANSACTIONS.md) — Transaction pattern usage
|
||||
|
||||
## Navigation
|
||||
|
||||
Per the AI Agent Core Protocol (folder navigation rule), start from this README when browsing `docs/`. All docs at this level are single-file reference.
|
||||
|
||||
## See also
|
||||
|
||||
- **Repo-level conventions**: `../../docs/CONVENTIONS.md`
|
||||
- **Core DTOs**: `../Mango.Nop.Core/docs/DTOS.md`
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
# Repository Pattern
|
||||
|
||||
> Part of `Mango.Nop.Data`. See `Mango.Nop.Data/README.md` for project overview.
|
||||
> For transaction patterns see `docs/TRANSACTIONS.md`.
|
||||
|
||||
## MgDbTableBase\<TEntity\>
|
||||
|
||||
Repository base wrapping nopCommerce `EntityRepository<TEntity>`.
|
||||
|
||||
**Constructor:**
|
||||
```csharp
|
||||
MgDbTableBase(IEventPublisher, INopDataProvider, IShortTermCacheManager, IStaticCacheManager, AppSettings)
|
||||
```
|
||||
|
||||
### Features
|
||||
|
||||
| Feature | Detail |
|
||||
|---|---|
|
||||
| `GetAll()` | Returns `IQueryable<TEntity>` from `Table` property |
|
||||
| Automatic timestamps | `ITimeStampCreated.Created` set on insert; `ITimeStampModified.Modified` set on insert/update |
|
||||
| CRUD hooks | `OnInsert(entity)`, `OnUpdate(entity)`, `OnDelete(entity)` — virtual, overridable |
|
||||
| Cache clear | `OnUpdate` clears `IStaticCacheManager` (currently clears all — TODO noted in code) |
|
||||
| All CRUD overrides | Overrides all sync/async `Insert`, `Update`, `Delete` methods to call hooks before `base.*` |
|
||||
| `DeleteAsync(int entityId)` | Convenience: load by id then delete |
|
||||
| `DeleteAsync(predicate, bool publishEvent)` | When `publishEvent=true`, loads entities first then deletes with events |
|
||||
|
||||
## MgDtoDbTableBase\<TDtoEntity, TMainEntity\>
|
||||
|
||||
DTO-aware repository for when the DTO entity (`TDtoEntity`) maps to a different main nopCommerce entity (`TMainEntity`). This is needed because LinqToDB tables are registered for DTOs, but nopCommerce events must fire on the main entity type.
|
||||
|
||||
### Features
|
||||
|
||||
| Feature | Detail |
|
||||
|---|---|
|
||||
| `GetMainEntityById(id)` | Loads `TMainEntity` from `INopDataProvider.GetTable<TMainEntity>()` |
|
||||
| `DeleteMainEntityById(id)` | Deletes the **main entity** (not the DTO) and publishes `EntityDeletedEvent<TMainEntity>` |
|
||||
| Delete overrides | **All Delete methods throw** — forces callers to use `DeleteMainEntityById()` instead |
|
||||
| Event bridging | `EntityInsertedEvent<TDtoEntity>` -> loads main entity -> publishes `EntityInsertedEvent<TMainEntity>` |
|
||||
| Event bridging | `EntityUpdatedEvent<TDtoEntity>` -> loads main entity -> publishes `EntityUpdatedEvent<TMainEntity>` |
|
||||
| Event bridging | `EntityDeletedEvent<TDtoEntity>` -> **throws** (must use `DeleteMainEntityById`) |
|
||||
|
||||
**Critical rule:** Never call `Delete` on a `MgDtoDbTableBase` repository directly. Always use `DeleteMainEntityById(int id)`.
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
# Transaction Pattern
|
||||
|
||||
> Part of `Mango.Nop.Data`. See `Mango.Nop.Data/README.md` for project overview.
|
||||
> For repository base classes see `docs/REPOSITORIES.md`.
|
||||
|
||||
## MgDbContextBase
|
||||
|
||||
Abstract database context base. NOT an EF Core DbContext — wraps `INopDataProvider` and `IRepository<T>` nopCommerce repos.
|
||||
|
||||
**Constructor:**
|
||||
```csharp
|
||||
MgDbContextBase(IRepository<Product>, IRepository<Order>, IRepository<OrderItem>, INopDataProvider, IMgLockService, ILogger)
|
||||
```
|
||||
|
||||
### Standard Repositories
|
||||
|
||||
| Property | Type |
|
||||
|---|---|
|
||||
| `Orders` | `IRepository<Order>` |
|
||||
| `OrderItems` | `IRepository<OrderItem>` |
|
||||
| `Products` | `IRepository<Product>` |
|
||||
| `DataProvider` | `INopDataProvider` (LinqToDB raw queries) |
|
||||
| `Logger` | Mango `ILogger` |
|
||||
| `LockService` | `IMgLockService` (global `SemaphoreSlim`) |
|
||||
|
||||
### 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 (`Complete()`), `false` to rollback.
|
||||
|
||||
**Isolation level:** `ReadCommitted`
|
||||
|
||||
**Error handling:** Catches exceptions, logs, returns `false` (unless `throwException = true`).
|
||||
|
||||
**TransactionSafe variants:** Use `LockService.SemaphoreSlim` for global serialization. Use for order creation, stock adjustment — any operation where concurrent modifications would corrupt data.
|
||||
|
||||
**Async variants:** Run on thread pool via `TaskHelper.ToThreadPoolTask()`.
|
||||
|
||||
## MgDalBase\<TDbContext\>
|
||||
|
||||
Data Access Layer orchestrator. Thin wrapper exposing:
|
||||
|
||||
| Property | Type | Purpose |
|
||||
|---|---|---|
|
||||
| `Name` | `string` | DAL instance name |
|
||||
| `Context` | `TDbContext` | The DB context (typed) |
|
||||
| `MutextLock` | `Mutex` | Cross-process locking |
|
||||
|
|
@ -47,4 +47,10 @@
|
|||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="docs\**\*.md" />
|
||||
<None Include="**\README.md" Exclude="$(DefaultItemExcludes);docs\**" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
# Mango.Nop.Services
|
||||
|
||||
@project {
|
||||
type = "framework"
|
||||
own-dep-projects = [
|
||||
"AyCode.Core, AyCode.Core.Server, AyCode.Entities, AyCode.Entities.Server, AyCode.Interfaces, AyCode.Interfaces.Server, AyCode.Utils (in AyCode.Core repo)"
|
||||
]
|
||||
}
|
||||
|
||||
Service base classes for nopCommerce plugin development — background tasks, session management, events, locking, logging. **net9.0**.
|
||||
|
||||
## Documentation
|
||||
|
||||
| Document | Topic |
|
||||
|---|---|
|
||||
| `SERVICES.md` | MgBackgroundServiceBase, MgSessionServiceBase, MgEventConsumerBase, MgLockServiceBase |
|
||||
| `LOGGING/README.md` | NopLogWriter — AyCode-to-nopCommerce log bridge, TransactionScope(Suppress) |
|
||||
|
||||
## Folder Structure
|
||||
|
||||
| Folder | Purpose |
|
||||
|---|---|
|
||||
| `Loggers/` | `NopLogWriter`, `NopLoggerMsSqlNopDataProvider` — AyCode -> nopCommerce log bridge |
|
||||
| *(root)* | `MgBackgroundServiceBase`, `MgSessionServiceBase`, `MgEventConsumerBase`, `MgLockServiceBase`, interfaces |
|
||||
|
||||
## Dependencies
|
||||
|
||||
- `Mango.Nop.Core`, `Mango.Nop.Data` (ProjectReferences)
|
||||
- `Nop.Core`, `Nop.Data`, `Nop.Services`, `Nop.Web.Framework` (nopCommerce ProjectReferences)
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
# NopLogWriter — Logging Bridge
|
||||
|
||||
> Part of `Mango.Nop.Services`. See `Mango.Nop.Services/README.md` for project overview.
|
||||
> For AyCode base logging types (`AcLogItemWriterBase`, `AcLogItem`, log levels) see `AyCode.Core/AyCode.Core/docs/LOGGING/README.md`.
|
||||
|
||||
## Overview
|
||||
|
||||
Bridges AyCode logging to nopCommerce's `Nop.Core.Domain.Logging.Log` table via direct DB insert.
|
||||
|
||||
## NopLogWriter
|
||||
|
||||
| Feature | Detail |
|
||||
|---|---|
|
||||
| Inherits | `AcLogItemWriterBase<AcLogItem>` (AyCode.Core) |
|
||||
| Log level mapping | AyCode `Detail/Trace/Debug/Info` -> nopCommerce `Information`; `Suggest/Warning` -> `Warning`; `Error` -> `Error` |
|
||||
| Direct DB insert | Uses `NopLoggerMsSqlNopDataProvider` with `TransactionScope(Suppress)` to avoid transaction conflicts |
|
||||
|
||||
**Constructor:** `(INopLoggerMsSqlNopDataProvider, CommonSettings, CustomerSettings, IWebHelper, Nop.Services.Logging.ILogger, string? categoryName)`
|
||||
|
||||
## NopLoggerMsSqlNopDataProvider
|
||||
|
||||
Extends `MsSqlNopDataProvider`. Provides isolated DB access for log writes.
|
||||
|
||||
| Method | Purpose |
|
||||
|---|---|
|
||||
| `InsertLogItem<T>()` | Sync insert with own `TransactionScope(Suppress, ReadUncommitted)` |
|
||||
| `InsertLogItemAsync<T>()` | Async insert with own `TransactionScope(Suppress, ReadUncommitted)` |
|
||||
|
||||
The `TransactionScope(Suppress)` is critical — without it, log writes would participate in the caller's transaction, causing nesting conflicts and potential deadlocks.
|
||||
|
||||
## Integration Point
|
||||
|
||||
```
|
||||
Application code -> Mango.Nop.Core.Loggers.ILogger (extends IAcLoggerBase)
|
||||
-> Logger<TCategory> (extends AcLoggerBase, delegates to IAcLogWriterBase[])
|
||||
-> NopLogWriter -> Nop Log table (direct SQL insert)
|
||||
-> [Other AyCode log writers: console, file, SignalR, etc.]
|
||||
```
|
||||
|
||||
**Exception:** `MgBackgroundServiceBase` uses `Nop.Services.Logging.ILogger` directly (nopCommerce logger), not the Mango wrapper.
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# Mango.Nop.Services documentation
|
||||
|
||||
Topic documentation for the `Mango.Nop.Services` project (Layer 2, service patterns).
|
||||
|
||||
## Reference docs (flat)
|
||||
|
||||
- [`SERVICES.md`](SERVICES.md) — Service pattern usage
|
||||
|
||||
## Topic folders
|
||||
|
||||
- [`LOGGING/`](LOGGING/README.md) — Logger bridge between NopCommerce's logger and AyCode.Core's logger (project-specific variant)
|
||||
|
||||
## Navigation
|
||||
|
||||
Per the AI Agent Core Protocol (folder navigation rule), start from this README when browsing `docs/`. Single-file reference docs remain flat; project-specific variants of framework topics (like LOGGING) live in named subfolders.
|
||||
|
||||
## See also
|
||||
|
||||
- **Base logger** (framework): `../../../../../Aycode/Source/AyCode.Core/AyCode.Core/docs/LOGGING/README.md`
|
||||
- **Remote logger variant**: `../../../../../Aycode/Source/AyCode.Core/AyCode.Services/docs/LOGGING/README.md`
|
||||
- **Server-side logger variant**: `../../../../../Aycode/Source/AyCode.Core/AyCode.Core.Server/docs/LOGGING/README.md`
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
# Service Base Classes
|
||||
|
||||
> Part of `Mango.Nop.Services`. See `Mango.Nop.Services/README.md` for project overview.
|
||||
> For logging bridge see `docs/LOGGING/README.md`.
|
||||
|
||||
## MgBackgroundServiceBase
|
||||
|
||||
Abstract hosted background service. Inherits `Microsoft.Extensions.Hosting.BackgroundService`.
|
||||
|
||||
**Constructor:** `(ILogger, IServiceProvider, int executeIntervalMs)`
|
||||
|
||||
| Feature | Detail |
|
||||
|---|---|
|
||||
| Loop pattern | `ExecuteAsync` loops: `Task.Delay(ExecuteIntervalMs)` -> `OnExecuteAsync()`, with pause support |
|
||||
| `OnExecuteAsync(CancellationToken)` | Abstract — subclass implements the actual work |
|
||||
| `Pause(bool)` | Pauses/resumes the loop without stopping the service |
|
||||
| `ExecuteIntervalMs` | Configurable interval between iterations |
|
||||
| Exception handling | Catches and logs errors per iteration, never crashes the loop |
|
||||
| Logging | Uses nopCommerce `Nop.Services.Logging.ILogger` (**not** `Mango.Nop.Core.Loggers.ILogger`) |
|
||||
|
||||
**Interface:** `IMgBackgroundService : IHostedService, IDisposable`
|
||||
|
||||
## MgSessionServiceBase\<TSessionItem\>
|
||||
|
||||
In-memory session management using `ConcurrentDictionary<string, TSessionItem>`.
|
||||
|
||||
| Method | Signature | Purpose |
|
||||
|---|---|---|
|
||||
| `GetOrCreateSessionItem` | `(string sessionId) -> TSessionItem?` | Get existing or create new via `Activator.CreateInstance` |
|
||||
| `TryAddSessionItem` | `(TSessionItem) -> bool` | Add if not exists, throws if duplicate |
|
||||
| `TryGetSessionItem` | `(string sessionId, out TSessionItem) -> bool` | Try-pattern lookup |
|
||||
| `TryRemoveSessionItem` | `(string sessionId, out TSessionItem) -> bool` | Remove and return |
|
||||
| `TryGetSessionItemBySignlaRConnectionId` | `(string connectionId, out TSessionItem?) -> bool` | Find session by SignalR connection |
|
||||
| `Count` | `() -> int` | Active session count |
|
||||
|
||||
**Interface:** `IMgSessionService<TSessionItem> where TSessionItem : IMgSessionItem`
|
||||
|
||||
## MgSessionItemBase
|
||||
|
||||
Base session item. Primary constructor: `(string sessionKey)`.
|
||||
|
||||
| Property | Type | Purpose |
|
||||
|---|---|---|
|
||||
| `SessionId` | `string` | Unique session identifier |
|
||||
| `SignaRConnectionId` | `string?` | Associated SignalR connection ID |
|
||||
| `RequestCount` | `int` | Request counter |
|
||||
|
||||
**Interface:** `IMgSessionItem` — `SessionId`, `SignaRConnectionId`, `RequestCount`
|
||||
|
||||
## MgEventConsumerBase
|
||||
|
||||
Abstract nopCommerce event consumer. Subscribes to:
|
||||
|
||||
| Event | Handler |
|
||||
|---|---|
|
||||
| `EntityUpdatedEvent<Product>` | `HandleEventAsync(...)` — virtual, empty default |
|
||||
| `EntityInsertedEvent<Product>` | `HandleEventAsync(...)` — virtual, empty default |
|
||||
| `CustomerRegisteredEvent` | `HandleEventAsync(...)` — virtual, empty default |
|
||||
| `OrderPlacedEvent` | `HandleEventAsync(...)` — virtual, empty default |
|
||||
| `PageRenderingEvent` | `HandleEventAsync(...)` — virtual, empty default |
|
||||
| `ProductSearchEvent` | `HandleEventAsync(...)` — virtual, empty default |
|
||||
|
||||
Built-in helper: `CheckAndUpdateProductManageInventoryMethodToManageStock(Product)` — ensures product has `ManageStock` inventory method.
|
||||
|
||||
**Constructor:** `(IMgDbContextBase ctx, IHttpContextAccessor, IEnumerable<IAcLogWriterBase> logWriters)`
|
||||
|
||||
## MgLockServiceBase
|
||||
|
||||
Simple in-process lock using `SemaphoreSlim(1)`. Implements `IMgLockService` (defined in `Mango.Nop.Core.Services`).
|
||||
|
||||
Used by `MgDbContextBase.TransactionSafe*` variants for global serialization.
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
# Mango.Nop Libraries
|
||||
|
||||
> For library domain rules see: `.github/copilot-instructions.md`
|
||||
> For detailed docs see: `docs/`
|
||||
|
||||
Shared nopCommerce extension libraries providing domain entities, DTOs, data access, and service base classes. All target **net9.0** (nopCommerce 4.80.9 requirement).
|
||||
|
||||
## Projects
|
||||
|
||||
| Project | Purpose | Key Types |
|
||||
|---|---|---|
|
||||
| `Mango.Nop.Core` | Domain entities, DTOs, interfaces, nopCommerce entity mirrors (zero nopCommerce runtime dep) | `MgEntityBase`, `ModelDtoBase<T>`, `MgOrderDto<,>`, `MgOrderItemDto<>`, `MgProductDto`, `CustomerDto`, `MgGenericAttributeDto`, `MgStockTaking<>`, `GenericAttributeExtensions` |
|
||||
| `Mango.Nop.Data` | Data access layer — repository base classes, DB context, transactions | `MgDbTableBase<T>`, `MgDtoDbTableBase<,>`, `MgDbContextBase`, `MgDalBase<T>` |
|
||||
| `Mango.Nop.Services` | Service base classes — background services, session, events, locking, logging | `MgBackgroundServiceBase`, `MgSessionServiceBase<T>`, `MgEventConsumerBase`, `MgLockServiceBase`, `NopLogWriter` |
|
||||
|
||||
## Dependency Graph
|
||||
|
||||
See `docs/ARCHITECTURE.md` for full dependency graph, project roles, DTO mapping strategies, and transaction patterns.
|
||||
|
||||
```
|
||||
AyCode.Core (DLL references)
|
||||
↑
|
||||
Mango.Nop.Core (net9.0, zero 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
|
||||
```
|
||||
|
||||
## Reference Modes
|
||||
|
||||
- **Full stack** (ProjectReference, all 3 libraries) — for nopCommerce plugins that need entity access, data layer, and services.
|
||||
- **Types only** (DLL reference, `Mango.Nop.Core` only) — for projects that only need DTOs, entities, and interfaces without the nopCommerce runtime dependency.
|
||||
|
||||
## Documentation Map
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `.github/copilot-instructions.md` | **Domain rules** — single source of truth for all conventions |
|
||||
| `docs/ARCHITECTURE.md` | Dependency graph, project roles, DTO strategies, transaction patterns, logging architecture |
|
||||
| `docs/CONVENTIONS.md` | Naming, patterns, project boundaries, AyCode integration points |
|
||||
| `docs/GLOSSARY.md` | Term definitions — entity/DTO system, data access, services, AyCode types |
|
||||
| `Mango.Nop.Core/README.md` | Core project overview — entity hierarchy, loggers, extensions, models |
|
||||
| `Mango.Nop.Core/docs/DTOS.md` | DTO system — two mapping strategies, all DTO types, GenericAttribute access |
|
||||
| `Mango.Nop.Core/docs/NOP_DEPENDENCIES.md` | NopDependencies pattern — mirror copies, namespace rules, file list |
|
||||
| `Mango.Nop.Data/README.md` | Data project overview — repository and context hierarchy, interfaces |
|
||||
| `Mango.Nop.Data/docs/REPOSITORIES.md` | MgDbTableBase, MgDtoDbTableBase — CRUD hooks, timestamps, delete rules |
|
||||
| `Mango.Nop.Data/docs/TRANSACTIONS.md` | MgDbContextBase — 4 transaction methods, lock strategy, callback contract |
|
||||
| `Mango.Nop.Services/README.md` | Services project overview |
|
||||
| `Mango.Nop.Services/docs/SERVICES.md` | MgBackgroundServiceBase, MgSessionServiceBase, MgEventConsumerBase, MgLockServiceBase |
|
||||
| `Mango.Nop.Services/docs/LOGGING/README.md` | NopLogWriter — AyCode-to-nopCommerce log bridge |
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
# 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/AyCode.Core/docs/LOGGING/README.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/AyCode.Core/docs/LOGGING/README.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)
|
||||
```
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
# Conventions
|
||||
|
||||
## Naming
|
||||
|
||||
- **`Mg` prefix** for all custom types: `MgEntityBase`, `MgOrderDto`, `MgDbTableBase`, `MgDalBase`, etc.
|
||||
- **`I` + name** for interfaces: `IMgDalBase`, `IMgDbTableBase`, `IMgOrderDto`, `IMgLockService`.
|
||||
- **`Dto` suffix** for DTOs wrapping nopCommerce entities: `MgOrderDto`, `MgProductDto`, `MgOrderItemDto`.
|
||||
- **`DbTable` suffix** for repository classes: `MgDbTableBase`, `MgDtoDbTableBase`.
|
||||
- **`Base` suffix** for abstract base classes: `MgEntityBase`, `ModelDtoBase`, `MgBackgroundServiceBase`.
|
||||
- **`Nop` prefix** for nopCommerce bridge types: `NopLogWriter`, `NopLoggerMsSqlNopDataProvider`, `NopCommonConst`.
|
||||
|
||||
## XML Documentation
|
||||
|
||||
`<summary>` — brief, developer-facing, readable in VS IntelliSense tooltip. NO implementation details, NO wire-format / byte-level / perf specifics — those live in `docs/TOPIC/*.md`. Add `<example>` only when usage is non-obvious; otherwise omit.
|
||||
|
||||
## Patterns
|
||||
|
||||
### DTO Bidirectional Mapping
|
||||
- `ModelDtoBase<TMainEntity>` provides `CopyEntityValuesToDto(entity)`, `CopyDtoValuesToEntity(entity)`, and `CreateMainEntity()`. Override all three in concrete DTOs.
|
||||
- Simple DTOs (e.g. `CustomerDto`) — manual property-by-property copy in overrides.
|
||||
- Complex DTOs (e.g. `MgOrderDto`) — use `PropertyHelper.CopyPublicValueTypeProperties(source, target)` for automatic value-type property copy, then manually set reference/navigation properties.
|
||||
|
||||
### LinqToDB Associations
|
||||
- DTOs with navigation properties use `[Association(ThisKey, OtherKey, CanBeNull)]` from LinqToDB.
|
||||
- `ThisKey` = local FK property name, `OtherKey` = target entity property name (typically `Id` or via interface member like `nameof(IMgProductDto.Id)`).
|
||||
|
||||
### NopDependencies Mirror
|
||||
- Entity classes in `NopDependencies/` use the **same namespace** as the original nopCommerce types. Do not change namespaces.
|
||||
- All mirror classes are `partial` — they can be extended but should not be modified directly.
|
||||
|
||||
### GenericAttribute Typed Access
|
||||
- Use `GenericAttributeExtensions.GetValueOrDefault<T>()` / `GetValueOrNull<T>()` / `TryGetValue<T>()` instead of raw string parsing.
|
||||
- Use `AddNewGenericAttribute()` to create new attributes with automatic UTC timestamp.
|
||||
|
||||
### Repository Base Chain
|
||||
- `MgDbTableBase<TEntity>` → `EntityRepository<TEntity>` (nopCommerce). Override virtual `OnInsert`/`OnUpdate`/`OnDelete` hooks, don't replace the chain.
|
||||
- `MgDtoDbTableBase<TDtoEntity, TMainEntity>` → `MgDbTableBase<TDtoEntity>`. **Never call Delete directly** — always use `DeleteMainEntityById(int id)`.
|
||||
|
||||
### Timestamp Interfaces
|
||||
- Entities implementing `ITimeStampCreated` get `Created = DateTime.UtcNow` on insert.
|
||||
- Entities implementing `ITimeStampModified` get `Modified = DateTime.UtcNow` on insert and update.
|
||||
- `ITimeStampInfo` combines both (`Creator`, `Created`, `Modified`).
|
||||
|
||||
### Transaction Pattern
|
||||
- Use `MgDbContextBase.TransactionSafeAsync()` for operations needing global lock (order creation, stock adjustment).
|
||||
- Callback returns `bool` — `true` commits, `false` rolls back.
|
||||
- Exceptions are caught and logged by default (return `false`). Pass `throwException: true` only for fail-fast scenarios.
|
||||
|
||||
### Event Consumer Pattern
|
||||
- Inherit `MgEventConsumerBase` and override relevant `HandleEventAsync` methods.
|
||||
- Base class handles DI of `IMgDbContextBase`, `IHttpContextAccessor`, and `IAcLogWriterBase[]`.
|
||||
- Base provides `CheckAndUpdateProductManageInventoryMethodToManageStock(Product)` helper.
|
||||
|
||||
### Session Pattern
|
||||
- Inherit `MgSessionServiceBase<TSessionItem>` and `MgSessionItemBase`.
|
||||
- Sessions stored in `ConcurrentDictionary<string, TSessionItem>` — thread-safe, in-memory only.
|
||||
- Session items track `SessionId`, `SignaRConnectionId`, `RequestCount`.
|
||||
|
||||
### Logging
|
||||
- Base logging infrastructure (`IAcLoggerBase`, `IAcLogWriterBase`, `AcLoggerBase`, `AcLogItemWriterBase`) — see `AyCode.Core/AyCode.Core/docs/LOGGING/README.md`.
|
||||
- Services create loggers via `new Logger<TCategory>(logWriters.ToArray())` in constructor.
|
||||
- `logWriters` injected as `IEnumerable<IAcLogWriterBase>` — typically contains `NopLogWriter` + other writers.
|
||||
- **Exception:** `MgBackgroundServiceBase` uses `Nop.Services.Logging.ILogger` directly (nopCommerce logger), not the Mango wrapper.
|
||||
|
||||
### Serialization Attributes
|
||||
- `[ToonDescription(...)]` — AyCode metadata for AI/doc tooling. `Purpose`, `BusinessRule`, `TypeRelation`, `RelatedTypes` properties.
|
||||
- `[AcBinarySerializable(false, true, false, true, false)]` — AcBinarySerializer config (see `AyCode.Core/AyCode.Core/docs/BINARY/BINARY_FORMAT.md`). Parameters control serialization behavior for AcSignalR transport (see `AyCode.Core/AyCode.Services/docs/SIGNALR/README.md`).
|
||||
- LinqToDB `[Table(Name = "...")]` and `[Association(...)]` — DB mapping.
|
||||
|
||||
## Project Boundaries
|
||||
|
||||
- `Mango.Nop.Core` — NO nopCommerce runtime dependency. Only NopDependencies mirrors. No `Nop.Data`, `Nop.Services` references.
|
||||
- `Mango.Nop.Data` — depends on nopCommerce data layer (`Nop.Core`, `Nop.Data`). No `Nop.Services` reference.
|
||||
- `Mango.Nop.Services` — depends on full nopCommerce stack (includes `Nop.Services`, `Nop.Web.Framework`).
|
||||
|
||||
## AyCode Integration Points
|
||||
|
||||
Key AyCode types used across these libraries:
|
||||
- `IEntityInt` (AyCode.Interfaces.Entities) — `int Id` entity contract
|
||||
- `IBaseEntity` — defined locally in NopDependencies, mirrors AyCode's concept
|
||||
- `IAcLoggerBase`, `IAcLogWriterBase`, `AcLoggerBase`, `AcLogItemWriterBase` — logging infrastructure (see `AyCode.Core/AyCode.Core/docs/LOGGING/README.md`)
|
||||
- `IAcModelDtoBaseEmpty` — DTO marker interface
|
||||
- `IAcSoftRemoveEntity`, `IAcSoftRemoveEntityInt` — soft-delete contracts
|
||||
- `IForeignKey`, `IForeignCollection<T>` — FK marker interfaces
|
||||
- `ITimeStampCreated`, `ITimeStampModified`, `ITimeStampInfo` — timestamp contracts
|
||||
- `PropertyHelper.CopyPublicValueTypeProperties()` — reflection-based property copy
|
||||
- `TaskHelper.ToThreadPoolTask()` — wraps async work in thread pool
|
||||
- `AcConst` — abstract constants base
|
||||
- `ToonDescription` — metadata attribute for AI tooling
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
# Glossary
|
||||
|
||||
Terminology for the Mango.Nop Libraries. Read this before working on unfamiliar areas.
|
||||
|
||||
## Entity & DTO System
|
||||
|
||||
| Term | Definition |
|
||||
|---|---|
|
||||
| **BaseEntity** | nopCommerce root entity base with `int Id`. Mirror copy in `NopDependencies/`. Namespace: `Nop.Core`. |
|
||||
| **IBaseEntity** | Interface for `BaseEntity` (defined alongside it in NopDependencies). Only `int Id`. |
|
||||
| **MgEntityBase** | Custom entity base — inherits `BaseEntity`, implements `IEntityInt` (AyCode). `ToString()` → `"{TypeName}; Id: {Id}"`. |
|
||||
| **ModelDtoBase** | Non-generic DTO base — only `int Id`. Implements `IModelDtoBase`. |
|
||||
| **ModelDtoBase\<T\>** | Generic DTO base with bidirectional mapping: `CopyEntityValuesToDto()` reads from entity, `CopyDtoValuesToEntity()` writes to entity, `CreateMainEntity()` creates entity from DTO. Uses `Activator.CreateInstance<T>()`. |
|
||||
| **IModelDtoBase** | `IEntityInt` + `IModelDtoBaseEmpty`. Marker for all DTOs with `int Id`. |
|
||||
| **IModelDtoBase\<T\>** | Contract: `CreateMainEntity()`, `CopyDtoValuesToEntity()`, `CopyEntityValuesToDto()`. |
|
||||
| **NopDependencies** | Mirror copies of nopCommerce entity classes in `Mango.Nop.Core`. Same namespaces as originals. Eliminates full nopCommerce dependency for consumers that only need types. |
|
||||
| **GenericAttribute** | nopCommerce polymorphic key-value store. `KeyGroup` = owner type name, `EntityId` = owner ID, `Key` = attribute name, `Value` = string value. `CreatedOrUpdatedDateUTC` tracks last change. |
|
||||
| **PropertyHelper.CopyPublicValueTypeProperties** | AyCode utility — reflection-based copy of all public value-type properties between two objects. Used by complex DTOs (`MgOrderDto`, `MgOrderItemDto`). |
|
||||
| **ToonDescription** | AyCode metadata attribute for AI/doc tooling. Properties: `Purpose`, `BusinessRule`, `TypeRelation`, `RelatedTypes`. |
|
||||
| **AcBinarySerializable** | AyCode binary serialization attribute (AcBinarySerializer, see `AyCode.Core/AyCode.Core/docs/BINARY/BINARY_FORMAT.md`). Configures how a type is serialized for AcSignalR transport (see `AyCode.Core/AyCode.Services/docs/SIGNALR/README.md`). |
|
||||
|
||||
## Data Access
|
||||
|
||||
| Term | Definition |
|
||||
|---|---|
|
||||
| **MgDbTableBase\<T\>** | Repository base wrapping nopCommerce `EntityRepository<T>`. Adds `GetAll()` (`IQueryable<T>`), automatic timestamp management via `ITimeStampCreated`/`ITimeStampModified` interfaces, CRUD hooks (`OnInsert`, `OnUpdate`, `OnDelete`). |
|
||||
| **MgDtoDbTableBase\<TDto, TMain\>** | DTO-aware repository. **Delete operations throw** — must use `DeleteMainEntityById()`. Bridges DTO events → main entity events (`EntityInsertedEvent`, `EntityUpdatedEvent`). |
|
||||
| **MgDbContextBase** | Database context base. Exposes `IRepository<Order>`, `IRepository<OrderItem>`, `IRepository<Product>`, `INopDataProvider`. Provides 4 transaction methods (`Transaction`, `TransactionSafe`, `TransactionAsync`, `TransactionSafeAsync`). |
|
||||
| **MgDalBase\<T\>** | Data Access Layer orchestrator — `Name`, `Context` (typed `TDbContext`), `MutextLock` (cross-process `Mutex`). |
|
||||
| **TransactionSafe** | Transaction with global `SemaphoreSlim` lock. Prevents concurrent modifications. Use for order creation, stock changes. |
|
||||
| **EntityRepository\<T\>** | nopCommerce built-in repository base (`Nop.Data`). `MgDbTableBase` extends this. |
|
||||
| **INopDataProvider** | nopCommerce interface for raw LinqToDB data access. Used by `MgDbContextBase` and `MgDtoDbTableBase`. |
|
||||
|
||||
## Services
|
||||
|
||||
| Term | Definition |
|
||||
|---|---|
|
||||
| **MgBackgroundServiceBase** | Base for hosted background services. Loop: `Task.Delay(interval)` → `OnExecuteAsync()`. Supports pause. Per-iteration exception handling. Uses nopCommerce `ILogger`. |
|
||||
| **MgSessionServiceBase\<T\>** | In-memory session management via `ConcurrentDictionary<string, T>`. Thread-safe. Methods: `GetOrCreateSessionItem`, `TryAddSessionItem`, `TryGetSessionItem`, `TryRemoveSessionItem`, `TryGetSessionItemBySignlaRConnectionId`. |
|
||||
| **MgSessionItemBase** | Session item with `SessionId`, `SignaRConnectionId`, `RequestCount`. Primary constructor: `(string sessionKey)`. |
|
||||
| **MgEventConsumerBase** | nopCommerce event consumer base. Subscribes to: `EntityUpdatedEvent<Product>`, `EntityInsertedEvent<Product>`, `CustomerRegisteredEvent`, `OrderPlacedEvent`, `PageRenderingEvent`, `ProductSearchEvent`. All handlers virtual with empty default. |
|
||||
| **MgLockServiceBase** | `SemaphoreSlim(1)` wrapper. Implements `IMgLockService`. Used by `MgDbContextBase.TransactionSafe*`. |
|
||||
| **NopLogWriter** | Bridges AyCode logging (see `AyCode.Core/AyCode.Core/docs/LOGGING/README.md`) to nopCommerce `Log` table.
|
||||
| **NopLoggerMsSqlNopDataProvider** | Extends `MsSqlNopDataProvider`. Provides `InsertLogItem<T>()` / `InsertLogItemAsync<T>()` with own `TransactionScope(Suppress, ReadUncommitted)` to avoid transaction nesting. |
|
||||
|
||||
## AyCode Types (external, from DLL references)
|
||||
|
||||
| Term | Definition |
|
||||
|---|---|
|
||||
| **IEntityInt** | `int Id` entity contract (AyCode.Interfaces.Entities) |
|
||||
| **IAcLoggerBase** | Logger interface — see `AyCode.Core/AyCode.Core/docs/LOGGING/README.md` (`AyCode.Core.Loggers`) |
|
||||
| **IAcLogWriterBase** | Log writer interface — pluggable output sink (see `AyCode.Core/AyCode.Core/docs/LOGGING/README.md`) |
|
||||
| **AcLoggerBase** | Logger base class with category name and writer array (see `AyCode.Core/AyCode.Core/docs/LOGGING/README.md`) |
|
||||
| **AcLogItemWriterBase\<T\>** | Log writer base for structured log items (see `AyCode.Core/AyCode.Core/docs/LOGGING/README.md`) |
|
||||
| **IAcModelDtoBaseEmpty** | Empty DTO marker interface |
|
||||
| **IAcSoftRemoveEntity** | Soft-delete contract (AyCode) |
|
||||
| **IForeignKey** | FK marker interface |
|
||||
| **IForeignCollection\<T\>** | FK collection marker |
|
||||
| **ITimeStampCreated** | `Created` datetime property |
|
||||
| **ITimeStampModified** | `Modified` datetime property |
|
||||
| **ITimeStampInfo** | Combines `Creator` (int), `Created`, `Modified` |
|
||||
| **AcConst** | Abstract constants base class |
|
||||
| **TaskHelper.ToThreadPoolTask** | Wraps `Func<Task<T>>` into `Task.Run` on thread pool |
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# Mango.Nop Libraries documentation
|
||||
|
||||
Top-level documentation for the Mango.Nop shared libraries (Layer 2 — shared NopCommerce plugin framework).
|
||||
|
||||
## Reference docs (flat)
|
||||
|
||||
- [`ARCHITECTURE.md`](ARCHITECTURE.md) — Repo architecture overview
|
||||
- [`CONVENTIONS.md`](CONVENTIONS.md) — Coding conventions
|
||||
- [`GLOSSARY.md`](GLOSSARY.md) — Domain glossary
|
||||
|
||||
## Sub-projects with docs
|
||||
|
||||
- `Mango.Nop.Core/docs/` — Core entity mirrors, DTOs, architecture
|
||||
- `Mango.Nop.Data/docs/` — Repository and transaction patterns
|
||||
- `Mango.Nop.Services/docs/` — Service patterns, logger bridge
|
||||
|
||||
## Navigation
|
||||
|
||||
Per the AI Agent Core Protocol (folder navigation rule), start from this README when browsing `docs/`. Single-file reference docs remain flat at this level; multi-file topics live in named subfolders at the sub-project level.
|
||||
|
||||
## See also
|
||||
|
||||
- **Base framework**: `../../../../Aycode/Source/AyCode.Core/` (see each project's `docs/` folder).
|
||||
Loading…
Reference in New Issue