Browse Source

Orleans Grains inventory provider plugin

pull/161/head
gdlcf88 4 years ago
parent
commit
cd2b65f8ed
  1. 1
      Directory.Build.props
  2. 44
      EShop.sln
  3. 58
      docs/plugins/inventories/orleans-grains/README.md
  4. 1
      plugins/Inventories/OrleansGrains/README.md
  5. 18
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions.csproj
  6. 11
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/EShopPluginsInventoriesOrleansGrainsAbstractionsModule.cs
  7. 13
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/IInventoryGrain.cs
  8. 8
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/InventoryStateModel.cs
  9. 3
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/FodyWeavers.xml
  10. 30
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/FodyWeavers.xsd
  11. 18
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo.csproj
  12. 14
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/EShopPluginsInventoriesOrleansGrainsSiloModule.cs
  13. 18
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.csproj
  14. 10
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/EShopPluginsInventoriesOrleansGrainsModule.cs
  15. 68
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/InventoryGrain.cs
  16. 3
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/FodyWeavers.xml
  17. 30
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/FodyWeavers.xsd
  18. 19
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.csproj
  19. 28
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/EShopProductsOrleansGrainsInventoryDomainModule.cs
  20. 9
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/IInventoryGrainProvider.cs
  21. 21
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/InventoryGrainProvider.cs
  22. 109
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/OrleansGrainsProductInventoryProvider.cs
  23. 3
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/FodyWeavers.xml
  24. 30
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/FodyWeavers.xsd
  25. 16
      plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/EShopProductsOrleansGrainsInventoryDomainTestModule.cs
  26. 24
      plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests.csproj
  27. 43
      plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/FakeInventoryGrain.cs
  28. 48
      plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/OrleansGrainsProductInventoryProviderTests.cs
  29. 61
      plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/ProductsOrleansGrainsInventoryTestBase.cs
  30. 25
      plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/TestInventoryGrainProvider.cs

1
Directory.Build.props

@ -6,6 +6,7 @@
<EasyAbpPaymentServiceModuleVersion>2.0.11</EasyAbpPaymentServiceModuleVersion>
<EasyAbpAbpTagHelperPlusModuleVersion>0.8.2</EasyAbpAbpTagHelperPlusModuleVersion>
<DaprSdkVersion>1.7.0</DaprSdkVersion>
<OrleansVersion>3.6.2</OrleansVersion>
</PropertyGroup>
</Project>

44
EShop.sln

@ -359,6 +359,22 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyAbp.EShop.Products.Dapr
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyAbp.EShop.Plugins.Inventories.DaprActors.AspNetCore", "plugins\Inventories\DaprActors\src\EasyAbp.EShop.Plugins.Inventories.DaprActors.AspNetCore\EasyAbp.EShop.Plugins.Inventories.DaprActors.AspNetCore.csproj", "{3F0EA314-CCF4-4BB2-A8C1-79FAE4442884}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyAbp.EShop.Plugins.Inventories.OrleansGrains", "plugins\Inventories\OrleansGrains\src\EasyAbp.EShop.Plugins.Inventories.OrleansGrains\EasyAbp.EShop.Plugins.Inventories.OrleansGrains.csproj", "{83F6434F-74DC-4389-870D-46510E28C029}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OrleansGrains", "OrleansGrains", "{88D17635-75D7-48A1-B622-E6FB3DCACEF8}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8E978749-7972-4703-8A94-6A90080C78DE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions", "plugins\Inventories\OrleansGrains\src\EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions\EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions.csproj", "{AB3477DB-3457-4167-A086-BAD104D69604}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo", "plugins\Inventories\OrleansGrains\src\EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo\EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo.csproj", "{0D613460-A0AD-4EAF-B719-785FE65E97E8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyAbp.EShop.Products.OrleansGrainsInventory.Domain", "plugins\Inventories\OrleansGrains\src\EasyAbp.EShop.Products.OrleansGrainsInventory.Domain\EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.csproj", "{DB1C55BF-0C0D-488C-9AFC-992A3DED2EAD}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{F58B6EEF-5AFF-4B79-BC71-A2D8C71F5E77}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests", "plugins\Inventories\OrleansGrains\test\EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests\EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests.csproj", "{D652EBF0-27CA-44C2-BB78-F446B87377C7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -933,6 +949,26 @@ Global
{3F0EA314-CCF4-4BB2-A8C1-79FAE4442884}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3F0EA314-CCF4-4BB2-A8C1-79FAE4442884}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3F0EA314-CCF4-4BB2-A8C1-79FAE4442884}.Release|Any CPU.Build.0 = Release|Any CPU
{83F6434F-74DC-4389-870D-46510E28C029}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{83F6434F-74DC-4389-870D-46510E28C029}.Debug|Any CPU.Build.0 = Debug|Any CPU
{83F6434F-74DC-4389-870D-46510E28C029}.Release|Any CPU.ActiveCfg = Release|Any CPU
{83F6434F-74DC-4389-870D-46510E28C029}.Release|Any CPU.Build.0 = Release|Any CPU
{AB3477DB-3457-4167-A086-BAD104D69604}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AB3477DB-3457-4167-A086-BAD104D69604}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AB3477DB-3457-4167-A086-BAD104D69604}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AB3477DB-3457-4167-A086-BAD104D69604}.Release|Any CPU.Build.0 = Release|Any CPU
{0D613460-A0AD-4EAF-B719-785FE65E97E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0D613460-A0AD-4EAF-B719-785FE65E97E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0D613460-A0AD-4EAF-B719-785FE65E97E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0D613460-A0AD-4EAF-B719-785FE65E97E8}.Release|Any CPU.Build.0 = Release|Any CPU
{DB1C55BF-0C0D-488C-9AFC-992A3DED2EAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DB1C55BF-0C0D-488C-9AFC-992A3DED2EAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DB1C55BF-0C0D-488C-9AFC-992A3DED2EAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DB1C55BF-0C0D-488C-9AFC-992A3DED2EAD}.Release|Any CPU.Build.0 = Release|Any CPU
{D652EBF0-27CA-44C2-BB78-F446B87377C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D652EBF0-27CA-44C2-BB78-F446B87377C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D652EBF0-27CA-44C2-BB78-F446B87377C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D652EBF0-27CA-44C2-BB78-F446B87377C7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -1112,6 +1148,14 @@ Global
{485204B1-7603-4EA0-B3A4-73CB89B0D5BC} = {6E6FE4B9-4117-4F57-B219-EE47E4046096}
{733C51A3-19C8-45C4-8B22-3FD40CAF4EFB} = {485204B1-7603-4EA0-B3A4-73CB89B0D5BC}
{3F0EA314-CCF4-4BB2-A8C1-79FAE4442884} = {F468A386-5660-4888-981A-6ECF15182D32}
{88D17635-75D7-48A1-B622-E6FB3DCACEF8} = {9AC27747-E175-487F-92C9-434DEE543273}
{8E978749-7972-4703-8A94-6A90080C78DE} = {88D17635-75D7-48A1-B622-E6FB3DCACEF8}
{83F6434F-74DC-4389-870D-46510E28C029} = {8E978749-7972-4703-8A94-6A90080C78DE}
{AB3477DB-3457-4167-A086-BAD104D69604} = {8E978749-7972-4703-8A94-6A90080C78DE}
{0D613460-A0AD-4EAF-B719-785FE65E97E8} = {8E978749-7972-4703-8A94-6A90080C78DE}
{DB1C55BF-0C0D-488C-9AFC-992A3DED2EAD} = {8E978749-7972-4703-8A94-6A90080C78DE}
{F58B6EEF-5AFF-4B79-BC71-A2D8C71F5E77} = {88D17635-75D7-48A1-B622-E6FB3DCACEF8}
{D652EBF0-27CA-44C2-BB78-F446B87377C7} = {F58B6EEF-5AFF-4B79-BC71-A2D8C71F5E77}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {28315BFD-90E7-4E14-A2EA-F3D23AF4126F}

58
docs/plugins/inventories/orleans-grains/README.md

@ -0,0 +1,58 @@
# EShop.Plugins.Inventories.OrleansGrains
[![ABP version](https://img.shields.io/badge/dynamic/xml?style=flat-square&color=yellow&label=abp&query=%2F%2FProject%2FPropertyGroup%2FAbpVersion&url=https%3A%2F%2Fraw.githubusercontent.com%2FEasyAbp%2FEShop%2Fmaster%2FDirectory.Build.props)](https://abp.io)
[![NuGet](https://img.shields.io/nuget/v/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions.svg?style=flat-square)](https://www.nuget.org/packages/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions)
[![NuGet Download](https://img.shields.io/nuget/dt/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions.svg?style=flat-square)](https://www.nuget.org/packages/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions)
[![Discord online](https://badgen.net/discord/online-members/S6QaezrCRq?label=Discord)](https://discord.gg/S6QaezrCRq)
[![GitHub stars](https://img.shields.io/github/stars/EasyAbp/EShop?style=social)](https://www.github.com/EasyAbp/EShop)
EShop product-inventory implementation of [Orleans Grains](https://docs.microsoft.com/en-us/dotnet/orleans/grains).
## Installation
1. Install the following NuGet packages. ([see how](https://github.com/EasyAbp/EasyAbpGuide/blob/master/docs/How-To.md#add-nuget-packages))
* EasyAbp.EShop.Products.OrleansGrainsInventory.Domain _(install at EasyAbp.EShop.Products.Domain location)_
* EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo _(install at a host project to run Grains)_
2. Add `DependsOn(typeof(EShopXxxModule))` attribute to configure the module dependencies. ([see how](https://github.com/EasyAbp/EasyAbpGuide/blob/master/docs/How-To.md#add-module-dependencies))
3. Open `Program.cs` in the host project to create an Orleans Silo. (see Microsoft's [document](https://docs.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/server-configuration) for more information)
```csharp
builder.Host.AddAppSettingsSecretsJson()
.UseAutofac()
.UseSerilog()
.UseOrleans(c =>
{
c.UseLocalhostClustering() // for test only
.AddMemoryGrainStorage(InventoryGrain.StorageProviderName) // for test only
.Configure<ClusterOptions>(options =>
{
options.ClusterId = "my-first-cluster";
options.ServiceId = "MyEShopApp";
})
.ConfigureApplicationParts(
parts => parts.AddApplicationPart(typeof(InventoryGrain).Assembly).WithReferences());
});
```
## Usage
1. Configure the OrleansGrains inventory provider as default.
```csharp
Configure<EShopProductsOptions>(options =>
{
// Configure as the default inventory provider
options.DefaultInventoryProviderName = "OrleansGrains";
// Configure as the default inventory provider for MyProductGroup
options.Groups.Configure<MyProductGroup>(group =>
{
group.DefaultInventoryProviderName = "OrleansGrains";
});
});
```
> Better to use `OrleansGrainsProductInventoryProvider.OrleansGrainsProductInventoryProviderName` instead of `"OrleansGrains"` as the provider name.
2. Create a product and set `InventoryProviderName` to `OrleansGrains`. Then the product is specified to use the Orleans Grains inventory provider.

1
plugins/Inventories/OrleansGrains/README.md

@ -0,0 +1 @@
../../../docs/plugins/inventories/orleans-grains/README.md

18
plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions.csproj

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Orleans.Core.Abstractions" Version="$(OrleansVersion)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\modules\EasyAbp.EShop.Products\src\EasyAbp.EShop.Products.Domain.Shared\EasyAbp.EShop.Products.Domain.Shared.csproj" />
</ItemGroup>
</Project>

11
plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/EShopPluginsInventoriesOrleansGrainsAbstractionsModule.cs

@ -0,0 +1,11 @@
using EasyAbp.EShop.Products;
using Volo.Abp.Modularity;
namespace EasyAbp.EShop.Plugins.Inventories.OrleansGrains;
[DependsOn(
typeof(EShopProductsDomainSharedModule)
)]
public class EShopPluginsInventoriesOrleansGrainsAbstractionsModule : AbpModule
{
}

13
plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/IInventoryGrain.cs

@ -0,0 +1,13 @@
using System.Threading.Tasks;
using Orleans;
namespace EasyAbp.EShop.Plugins.Inventories.OrleansGrains;
public interface IInventoryGrain : IGrainWithStringKey
{
Task<InventoryStateModel> GetInventoryStateAsync();
Task IncreaseInventoryAsync(int quantity, bool decreaseSold);
Task ReduceInventoryAsync(int quantity, bool increaseSold);
}

8
plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/InventoryStateModel.cs

@ -0,0 +1,8 @@
namespace EasyAbp.EShop.Plugins.Inventories.OrleansGrains;
public class InventoryStateModel
{
public int Inventory { get; set; }
public long Sold { get; set; }
}

3
plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

18
plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo.csproj

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\EasyAbp.EShop.Plugins.Inventories.OrleansGrains\EasyAbp.EShop.Plugins.Inventories.OrleansGrains.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Orleans.Server" Version="$(OrleansVersion)" />
</ItemGroup>
</Project>

14
plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/EShopPluginsInventoriesOrleansGrainsSiloModule.cs

@ -0,0 +1,14 @@
using EasyAbp.EShop.Products;
using Volo.Abp.Modularity;
namespace EasyAbp.EShop.Plugins.Inventories.OrleansGrains;
[DependsOn(
typeof(EShopPluginsInventoriesOrleansGrainsModule)
)]
public class EShopPluginsInventoriesOrleansGrainsSiloModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
}
}

18
plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.csproj

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions\EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Orleans.Core.Abstractions" Version="$(OrleansVersion)" />
</ItemGroup>
</Project>

10
plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/EShopPluginsInventoriesOrleansGrainsModule.cs

@ -0,0 +1,10 @@
using Volo.Abp.Modularity;
namespace EasyAbp.EShop.Plugins.Inventories.OrleansGrains;
[DependsOn(
typeof(EShopPluginsInventoriesOrleansGrainsAbstractionsModule)
)]
public class EShopPluginsInventoriesOrleansGrainsModule : AbpModule
{
}

68
plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/InventoryGrain.cs

@ -0,0 +1,68 @@
using System.Threading.Tasks;
using Orleans;
using Orleans.Providers;
using Orleans.Runtime;
namespace EasyAbp.EShop.Plugins.Inventories.OrleansGrains;
[StorageProvider(ProviderName = StorageProviderName)]
public class InventoryGrain : Grain<InventoryStateModel>, IInventoryGrain
{
public const string StorageProviderName = "EShopInventoryStorage";
public virtual Task<InventoryStateModel> GetInventoryStateAsync() => Task.FromResult(State);
public virtual async Task IncreaseInventoryAsync(int quantity, bool decreaseSold)
{
InternalIncreaseInventory(quantity, decreaseSold);
await WriteStateAsync();
}
public async Task ReduceInventoryAsync(int quantity, bool increaseSold)
{
InternalReduceInventory(quantity, increaseSold);
await WriteStateAsync();
}
protected virtual void InternalIncreaseInventory(int quantity, bool decreaseSold)
{
if (quantity < 0)
{
throw new OrleansException("Quantity should not be less than 0.");
}
if (decreaseSold && State.Sold - quantity < 0)
{
throw new OrleansException("Target Sold cannot be less than 0.");
}
State.Inventory = checked(State.Inventory + quantity);
if (decreaseSold)
{
State.Sold -= quantity;
}
}
protected virtual void InternalReduceInventory(int quantity, bool increaseSold)
{
if (quantity < 0)
{
throw new OrleansException("Quantity should not be less than 0.");
}
if (quantity > State.Inventory)
{
throw new OrleansException("Insufficient inventory.");
}
if (increaseSold)
{
State.Sold = checked(State.Sold + quantity);
}
State.Inventory -= quantity;
}
}

3
plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

19
plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.csproj

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\modules\EasyAbp.EShop.Products\src\EasyAbp.EShop.Products.Domain\EasyAbp.EShop.Products.Domain.csproj" />
<ProjectReference Include="..\EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions\EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Orleans.Client" Version="$(OrleansVersion)" />
</ItemGroup>
</Project>

28
plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/EShopProductsOrleansGrainsInventoryDomainModule.cs

@ -0,0 +1,28 @@
using EasyAbp.EShop.Plugins.Inventories.OrleansGrains;
using EasyAbp.EShop.Products.Options;
using Volo.Abp.Modularity;
namespace EasyAbp.EShop.Products.OrleansGrainsInventory;
[DependsOn(
typeof(EShopProductsDomainModule),
typeof(EShopPluginsInventoriesOrleansGrainsAbstractionsModule)
)]
public class EShopProductsOrleansGrainsInventoryDomainModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<EShopProductsOptions>(options =>
{
options.InventoryProviders.Configure(
OrleansGrainsProductInventoryProvider.OrleansGrainsProductInventoryProviderName, provider =>
{
provider.DisplayName =
OrleansGrainsProductInventoryProvider.OrleansGrainsProductInventoryProviderDisplayName;
provider.Description = OrleansGrainsProductInventoryProvider
.OrleansGrainsProductInventoryProviderDescription;
provider.ProviderType = typeof(OrleansGrainsProductInventoryProvider);
});
});
}
}

9
plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/IInventoryGrainProvider.cs

@ -0,0 +1,9 @@
using System.Threading.Tasks;
using EasyAbp.EShop.Plugins.Inventories.OrleansGrains;
namespace EasyAbp.EShop.Products.OrleansGrainsInventory;
public interface IInventoryGrainProvider
{
Task<IInventoryGrain> GetAsync(string grainKey);
}

21
plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/InventoryGrainProvider.cs

@ -0,0 +1,21 @@
using System.Threading.Tasks;
using EasyAbp.EShop.Plugins.Inventories.OrleansGrains;
using Orleans;
using Volo.Abp.DependencyInjection;
namespace EasyAbp.EShop.Products.OrleansGrainsInventory;
public class InventoryGrainProvider : IInventoryGrainProvider, ITransientDependency
{
private readonly IGrainFactory _grainFactory;
public InventoryGrainProvider(IGrainFactory grainFactory)
{
_grainFactory = grainFactory;
}
public virtual Task<IInventoryGrain> GetAsync(string grainKey)
{
return Task.FromResult(_grainFactory.GetGrain<IInventoryGrain>(grainKey));
}
}

109
plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/OrleansGrainsProductInventoryProvider.cs

@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using EasyAbp.EShop.Plugins.Inventories.OrleansGrains;
using EasyAbp.EShop.Products.ProductInventories;
using Microsoft.Extensions.Logging;
using Volo.Abp.DependencyInjection;
namespace EasyAbp.EShop.Products.OrleansGrainsInventory;
public class OrleansGrainsProductInventoryProvider : IProductInventoryProvider, ITransientDependency
{
public static string OrleansGrainsProductInventoryProviderName { get; set; } = "OrleansGrains";
public static string OrleansGrainsProductInventoryProviderDisplayName { get; set; } = "OrleansGrains";
public static string OrleansGrainsProductInventoryProviderDescription { get; set; } = "OrleansGrains";
public string InventoryProviderName { get; } = OrleansGrainsProductInventoryProviderName;
private readonly ILogger<OrleansGrainsProductInventoryProvider> _logger;
protected IInventoryGrainProvider InventoryGrainProvider { get; }
public OrleansGrainsProductInventoryProvider(
IInventoryGrainProvider inventoryGrainProvider,
ILogger<OrleansGrainsProductInventoryProvider> logger)
{
InventoryGrainProvider = inventoryGrainProvider;
_logger = logger;
}
public virtual async Task<InventoryDataModel> GetInventoryDataAsync(InventoryQueryModel model)
{
var grain = await GetGrainAsync(model);
var stateModel = await grain.GetInventoryStateAsync();
return new InventoryDataModel
{
Inventory = stateModel.Inventory,
Sold = stateModel.Sold
};
}
public virtual async Task<Dictionary<Guid, InventoryDataModel>> GetSkuIdInventoryDataMappingAsync(
IList<InventoryQueryModel> models)
{
var result = new Dictionary<Guid, InventoryDataModel>();
foreach (var model in models)
{
result.Add(model.ProductSkuId, await GetInventoryDataAsync(model));
}
return result;
}
public virtual async Task<bool> TryIncreaseInventoryAsync(InventoryQueryModel model, int quantity,
bool decreaseSold)
{
var grain = await GetGrainAsync(model);
try
{
await grain.IncreaseInventoryAsync(quantity, decreaseSold);
}
catch (Exception e)
{
_logger.LogError("Grain threw: {Message}", e.Message);
return false;
}
return true;
}
public virtual async Task<bool> TryReduceInventoryAsync(InventoryQueryModel model, int quantity, bool increaseSold)
{
var grain = await GetGrainAsync(model);
var stateModel = await grain.GetInventoryStateAsync();
if (stateModel.Inventory < quantity)
{
return false;
}
try
{
await grain.ReduceInventoryAsync(quantity, increaseSold);
}
catch (Exception e)
{
_logger.LogError("Grain threw: {Message}", e.Message);
return false;
}
return true;
}
protected virtual async Task<IInventoryGrain> GetGrainAsync(InventoryQueryModel model)
{
return await InventoryGrainProvider.GetAsync(GetGrainId(model));
}
protected virtual string GetGrainId(InventoryQueryModel model)
{
return $"eshop_inventory_{(model.TenantId.HasValue ? model.TenantId.Value : "host")}_{model.ProductSkuId}";
}
}

3
plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

16
plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/EShopProductsOrleansGrainsInventoryDomainTestModule.cs

@ -0,0 +1,16 @@
using Volo.Abp;
using Volo.Abp.Authorization;
using Volo.Abp.Autofac;
using Volo.Abp.Modularity;
namespace EasyAbp.EShop.Products.OrleansGrainsInventory.Domain;
[DependsOn(
typeof(AbpAutofacModule),
typeof(AbpTestBaseModule),
typeof(AbpAuthorizationModule),
typeof(EShopProductsOrleansGrainsInventoryDomainModule)
)]
public class EShopProductsOrleansGrainsInventoryDomainTestModule : AbpModule
{
}

24
plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests.csproj

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>EasyAbp.EShop.Products.OrleansGrainsInventory.Domain</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="NSubstitute" Version="4.2.2" />
<PackageReference Include="Shouldly" Version="4.0.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.extensibility.execution" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="Volo.Abp.Autofac" Version="$(AbpVersion)" />
<PackageReference Include="Volo.Abp.Authorization" Version="$(AbpVersion)" />
<PackageReference Include="Volo.Abp.TestBase" Version="$(AbpVersion)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\EasyAbp.EShop.Products.OrleansGrainsInventory.Domain\EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.csproj" />
</ItemGroup>
</Project>

43
plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/FakeInventoryGrain.cs

@ -0,0 +1,43 @@
using System.Threading.Tasks;
using EasyAbp.EShop.Plugins.Inventories.OrleansGrains;
using Volo.Abp.DependencyInjection;
namespace EasyAbp.EShop.Products.OrleansGrainsInventory.Domain;
public class FakeInventoryGrain : IInventoryGrain, ITransientDependency
{
private InventoryStateModel StateModel { get; } = new()
{
Inventory = 100,
Sold = 0
};
public Task<InventoryStateModel> GetInventoryStateAsync()
{
return Task.FromResult(StateModel);
}
public Task IncreaseInventoryAsync(int quantity, bool decreaseSold)
{
StateModel.Inventory += quantity;
if (decreaseSold)
{
StateModel.Sold -= quantity;
}
return Task.CompletedTask;
}
public Task ReduceInventoryAsync(int quantity, bool increaseSold)
{
StateModel.Inventory -= quantity;
if (increaseSold)
{
StateModel.Sold += quantity;
}
return Task.CompletedTask;
}
}

48
plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/OrleansGrainsProductInventoryProviderTests.cs

@ -0,0 +1,48 @@
using System.Threading.Tasks;
using EasyAbp.EShop.Products.ProductInventories;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Xunit;
namespace EasyAbp.EShop.Products.OrleansGrainsInventory.Domain;
public class OrleansGrainsProductInventoryProviderTests : ProductsOrleansGrainsInventoryTestBase
{
[Fact]
public async Task Should_Get_Inventory()
{
var inventoryProvider = ServiceProvider.GetRequiredService<OrleansGrainsProductInventoryProvider>();
var inventoryDataModel = await inventoryProvider.GetInventoryDataAsync(new InventoryQueryModel());
inventoryDataModel.ShouldNotBeNull();
inventoryDataModel.Inventory.ShouldBe(100);
inventoryDataModel.Sold.ShouldBe(0);
}
[Fact]
public async Task Should_Change_Inventory()
{
var inventoryProvider = ServiceProvider.GetRequiredService<OrleansGrainsProductInventoryProvider>();
var result = await inventoryProvider.TryReduceInventoryAsync(new InventoryQueryModel(), 2, true);
result.ShouldBeTrue();
var inventoryDataModel = await inventoryProvider.GetInventoryDataAsync(new InventoryQueryModel());
inventoryDataModel.ShouldNotBeNull();
inventoryDataModel.Inventory.ShouldBe(98);
inventoryDataModel.Sold.ShouldBe(2);
result = await inventoryProvider.TryIncreaseInventoryAsync(new InventoryQueryModel(), 1, true);
result.ShouldBeTrue();
inventoryDataModel = await inventoryProvider.GetInventoryDataAsync(new InventoryQueryModel());
inventoryDataModel.ShouldNotBeNull();
inventoryDataModel.Inventory.ShouldBe(99);
inventoryDataModel.Sold.ShouldBe(1);
}
}

61
plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/ProductsOrleansGrainsInventoryTestBase.cs

@ -0,0 +1,61 @@
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
using Volo.Abp.Modularity;
using Volo.Abp.Testing;
using Volo.Abp.Uow;
namespace EasyAbp.EShop.Products.OrleansGrainsInventory.Domain
{
/* All test classes are derived from this class, directly or indirectly. */
public abstract class
ProductsOrleansGrainsInventoryTestBase : AbpIntegratedTest<EShopProductsOrleansGrainsInventoryDomainTestModule>
{
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.UseAutofac();
}
protected virtual Task WithUnitOfWorkAsync(Func<Task> func)
{
return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func);
}
protected virtual async Task WithUnitOfWorkAsync(AbpUnitOfWorkOptions options, Func<Task> action)
{
using (var scope = ServiceProvider.CreateScope())
{
var uowManager = scope.ServiceProvider.GetRequiredService<IUnitOfWorkManager>();
using (var uow = uowManager.Begin(options))
{
await action();
await uow.CompleteAsync();
}
}
}
protected virtual Task<TResult> WithUnitOfWorkAsync<TResult>(Func<Task<TResult>> func)
{
return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func);
}
protected virtual async Task<TResult> WithUnitOfWorkAsync<TResult>(AbpUnitOfWorkOptions options,
Func<Task<TResult>> func)
{
using (var scope = ServiceProvider.CreateScope())
{
var uowManager = scope.ServiceProvider.GetRequiredService<IUnitOfWorkManager>();
using (var uow = uowManager.Begin(options))
{
var result = await func();
await uow.CompleteAsync();
return result;
}
}
}
}
}

25
plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/TestInventoryGrainProvider.cs

@ -0,0 +1,25 @@
using System;
using System.Threading.Tasks;
using EasyAbp.EShop.Plugins.Inventories.OrleansGrains;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.DependencyInjection;
namespace EasyAbp.EShop.Products.OrleansGrainsInventory.Domain;
[Dependency(ReplaceServices = true)]
public class TestInventoryGrainProvider : IInventoryGrainProvider, ITransientDependency
{
private IInventoryGrain Grain { get; set; }
private readonly IServiceProvider _serviceProvider;
public TestInventoryGrainProvider(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public Task<IInventoryGrain> GetAsync(string grainKey)
{
return Task.FromResult(Grain ??= _serviceProvider.GetRequiredService<FakeInventoryGrain>());
}
}
Loading…
Cancel
Save