├── .gitattributes
├── .github
└── workflows
│ └── cd.yaml
├── .gitignore
├── Enbiso.NLib.Cqrs.Idempotent
├── Enbiso.NLib.Cqrs.Idempotent.csproj
├── IdempotentCommandBus.cs
└── ServiceExtensions.cs
├── Enbiso.NLib.Cqrs
├── Command.cs
├── CommandBus.cs
├── CommandLogger.cs
├── CommandProcessor.cs
├── CommandValidator.cs
├── Enbiso.NLib.Cqrs.csproj
├── IQuery.cs
└── ServiceExtensions.cs
├── Enbiso.NLib.DependencyInjection
├── Enbiso.NLib.DependencyInjection.csproj
├── ServiceAttributes.cs
└── ServiceExtensions.cs
├── Enbiso.NLib.Domain.Events
├── DomainEvent.cs
├── DomainEventBus.cs
├── Enbiso.NLib.Domain.Events.csproj
└── ServiceExtensions.cs
├── Enbiso.NLib.Domain
├── Enbiso.NLib.Domain.csproj
├── Entity.cs
├── Exception.cs
└── Repository.cs
├── Enbiso.NLib.EventBus.Abstractions
├── Enbiso.NLib.EventBus.Abstractions.csproj
├── IEvent.cs
├── IEventHandler.cs
├── IEventPublisher.cs
├── IEventService.cs
├── IEventSubscriber.cs
└── IEventSubscriptionService.cs
├── Enbiso.NLib.EventBus.AwsSns
├── AwsSnsConnection.cs
├── AwsSnsEventPublisher.cs
├── AwsSnsEventSubscriber.cs
├── AwsSnsOptions.cs
├── Enbiso.NLib.EventBus.AwsSns.csproj
└── ServiceExtensions.cs
├── Enbiso.NLib.EventBus.Nats
├── Enbiso.NLib.EventBus.Nats.csproj
├── JetStream
│ ├── JetStreamConnection.cs
│ ├── JetStreamEventPublisher.cs
│ └── JetStreamEventSubscriber.cs
├── NatsConnection.cs
├── NatsEventPublisher.cs
├── NatsEventSubscriber.cs
├── NatsOptions.cs
├── NatsPolicyBuilder.cs
└── ServiceExtensions.cs
├── Enbiso.NLib.EventBus.RabbitMq
├── Enbiso.NLib.EventBus.RabbitMq.csproj
├── RabbitMqBusPublisher.cs
├── RabbitMqBusSubscriber.cs
├── RabbitMqConnection.cs
├── RabbitMqOption.cs
└── ServiceExtensions.cs
├── Enbiso.NLib.EventBus
├── Enbiso.NLib.EventBus.csproj
├── Event.cs
├── EventProcessor.cs
├── EventService.cs
├── EventSubscriptionService.cs
├── EventTypeManager.cs
└── ServiceExtensions.cs
├── Enbiso.NLib.EventInfo
├── Enbiso.NLib.EventInfo.csproj
├── EventInfoController.cs
├── EventInfoService.cs
├── Models
│ ├── EventInfoListResponse.cs
│ ├── EventRecord.cs
│ ├── EventRecordMapper.cs
│ └── EventRecordProp.cs
└── ServiceExtensions.cs
├── Enbiso.NLib.EventLogger.EntityFramework
├── Enbiso.NLib.EventLogger.EntityFramework.csproj
├── EntityEventLogRepo.cs
├── EventLogEntityConfig.cs
└── ServiceExtensions.cs
├── Enbiso.NLib.EventLogger.Mongo
├── Enbiso.NLib.EventLogger.Mongo.csproj
├── MongoEventLogRepo.cs
└── ServiceExtensions.cs
├── Enbiso.NLib.EventLogger
├── Enbiso.NLib.EventLogger.csproj
├── EventLog.cs
├── EventLoggerEventService.cs
├── EventLoggerService.cs
├── IEventLogRepo.cs
└── ServiceExtensions.cs
├── Enbiso.NLib.GlobalExceptions
├── Enbiso.NLib.GlobalExceptions.csproj
├── GlobalExceptionFilter.cs
├── GlobalExceptionHandler.cs
├── GlobalExceptionHandlerExtensions.cs
└── GlobalExceptionResponse.cs
├── Enbiso.NLib.HttpContextService
├── Enbiso.NLib.HttpContextService.csproj
├── HttpContextFetcher.cs
├── HttpContextService.cs
└── ServiceExtensions.cs
├── Enbiso.NLib.Idempotency.EntityFramework
├── Enbiso.NLib.Idempotency.EntityFramework.csproj
├── RequestLogEntityConfig.cs
├── RequestLogRepo.cs
└── ServiceExtensions.cs
├── Enbiso.NLib.Idempotency
├── Enbiso.NLib.Idempotency.csproj
├── IRequestLogRepo.cs
├── IRequestManager.cs
├── RequestLog.cs
├── RequestManager.cs
└── ServiceExtensions.cs
├── Enbiso.NLib.IdentityServer.Mongo
├── Enbiso.NLib.IdentityServer.Mongo.csproj
├── Events
│ ├── IdentityServerMongoEvents.cs
│ └── IdentityServerMongoUserEvents.cs
├── Models
│ ├── ApiResourceData.cs
│ ├── ClientData.cs
│ ├── IMongoIdentityRole.cs
│ ├── IMongoIdentityUser.cs
│ ├── IdentityResourceData.cs
│ ├── MongoClaim.cs
│ ├── MongoUserLoginInfo.cs
│ ├── PersistedGrantData.cs
│ └── RecoveryCode.cs
├── ServiceExtensions.cs
└── Stores
│ ├── MongoClientStore.cs
│ ├── MongoPersistedGrantStore.cs
│ ├── MongoResourceStore.cs
│ ├── MongoRoleStore.cs
│ └── MongoUserStore.cs
├── Enbiso.NLib.OpenApi
├── Attributes
│ ├── Actions
│ │ ├── ExtActionAttribute.cs
│ │ ├── ExtActionCreateAttribute.cs
│ │ ├── ExtActionDeleteAttribute.cs
│ │ ├── ExtActionDetailsAttribute.cs
│ │ └── ExtActionUpdateAttribute.cs
│ ├── ExtAttribute.cs
│ ├── ExtHiddenAttribute.cs
│ ├── ExtKeyAttribute.cs
│ └── Inputs
│ │ ├── ExtInputAttribute.cs
│ │ ├── ExtInputColorAttribute.cs
│ │ ├── ExtInputDateAttribute.cs
│ │ ├── ExtInputDateTimeLocalAttribute.cs
│ │ ├── ExtInputEmailAttribute.cs
│ │ ├── ExtInputMonthAttribute.cs
│ │ ├── ExtInputNumberAttribute.cs
│ │ ├── ExtInputPasswordAttribute.cs
│ │ ├── ExtInputSearchAttribute.cs
│ │ ├── ExtInputTelAttribute.cs
│ │ ├── ExtInputTextAttribute.cs
│ │ ├── ExtInputTimeAttribute.cs
│ │ ├── ExtInputUrlAttribute.cs
│ │ └── ExtInputWeekAttribute.cs
├── Enbiso.NLib.OpenApi.csproj
├── SchemaExtensionFilter.cs
└── ServiceExtensions.cs
├── Enbiso.NLib.RestClient
├── Enbiso.NLib.RestClient.csproj
├── Exceptions.cs
├── RestClient.cs
└── ServiceExtensions.cs
├── Enbiso.NLib.Tests
├── Enbiso.NLib.Domain.Tests
│ ├── Enbiso.NLib.Domain.Tests.csproj
│ └── EntityTests.cs
└── Enbiso.NLib.OpenApi.Tests
│ ├── Enbiso.NLib.OpenApi.Tests.csproj
│ └── ServiceExtensionsTests.cs
├── Enbiso.NLib.sln
├── LICENSE
├── README.md
└── logo.png
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.github/workflows/cd.yaml:
--------------------------------------------------------------------------------
1 | name: CD - Nuget
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | env:
9 | PACKAGE_VERSION: 7.0.5
10 | PACKAGE_PROJECT: https://nlib.enbiso.com
11 | PACKAGE_REPO: https://github.com/enbiso/Enbiso.NLib
12 | PACKAGE_COPYRIGHT: Copyright 2021 (c) enbiso. All rights reserved.
13 |
14 | jobs:
15 | test:
16 | name: Unit Tests
17 | runs-on: ubuntu-latest
18 | steps:
19 | - name: Checkout
20 | uses: actions/checkout@v2
21 |
22 | - name: Setup .NET
23 | uses: actions/setup-dotnet@v1
24 | with:
25 | dotnet-version: 7.0.x
26 |
27 | - name: Test
28 | run: dotnet test --verbosity normal
29 |
30 | build:
31 | name: Build & Publish
32 | needs: [test]
33 | runs-on: ubuntu-latest
34 |
35 | steps:
36 | - name: Checkout
37 | uses: actions/checkout@v2
38 |
39 | - name: Setup .NET
40 | uses: actions/setup-dotnet@v1
41 | with:
42 | dotnet-version: 7.0.x
43 |
44 | - name: Build Release
45 | run: dotnet build -c release -o ./bin
46 |
47 | - name: Publish
48 | run: for nupkg in ./bin/*.nupkg; do
49 | dotnet nuget push $nupkg -s $NUGET_REGISTRY -k $NUGET_API_KEY;
50 | done
51 | env:
52 | NUGET_REGISTRY: https://packages.nuget.org
53 | NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
54 |
55 | release:
56 | name: Tags and Release
57 | needs: [build]
58 | runs-on: ubuntu-latest
59 |
60 | steps:
61 | - name: Create Release
62 | uses: actions/create-release@v1
63 | env:
64 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
65 | TAG_NAME: v${{ env.PACKAGE_VERSION }}
66 | with:
67 | tag_name: ${{ env.TAG_NAME }}
68 | release_name: Release ${{ env.TAG_NAME }}
69 | body: |
70 | Release ${{ env.TAG_NAME }}
71 | https://www.nuget.org/profiles/enbiso
72 | draft: false
73 | prerelease: false
74 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | project.fragment.lock.json
46 | artifacts/
47 |
48 | *_i.c
49 | *_p.c
50 | *_i.h
51 | *.ilk
52 | *.meta
53 | *.obj
54 | *.pch
55 | *.pdb
56 | *.pgc
57 | *.pgd
58 | *.rsp
59 | *.sbr
60 | *.tlb
61 | *.tli
62 | *.tlh
63 | *.tmp
64 | *.tmp_proj
65 | *.log
66 | *.vspscc
67 | *.vssscc
68 | .builds
69 | *.pidb
70 | *.svclog
71 | *.scc
72 |
73 | # Chutzpah Test files
74 | _Chutzpah*
75 |
76 | # Visual C++ cache files
77 | ipch/
78 | *.aps
79 | *.ncb
80 | *.opendb
81 | *.opensdf
82 | *.sdf
83 | *.cachefile
84 | *.VC.db
85 | *.VC.VC.opendb
86 |
87 | # Visual Studio profiler
88 | *.psess
89 | *.vsp
90 | *.vspx
91 | *.sap
92 |
93 | # TFS 2012 Local Workspace
94 | $tf/
95 |
96 | # Guidance Automation Toolkit
97 | *.gpState
98 |
99 | # ReSharper is a .NET coding add-in
100 | _ReSharper*/
101 | *.[Rr]e[Ss]harper
102 | *.DotSettings.user
103 |
104 | # JustCode is a .NET coding add-in
105 | .JustCode
106 |
107 | # TeamCity is a build add-in
108 | _TeamCity*
109 |
110 | # DotCover is a Code Coverage Tool
111 | *.dotCover
112 |
113 | # NCrunch
114 | _NCrunch_*
115 | .*crunch*.local.xml
116 | nCrunchTemp_*
117 |
118 | # MightyMoose
119 | *.mm.*
120 | AutoTest.Net/
121 |
122 | # Web workbench (sass)
123 | .sass-cache/
124 |
125 | # Installshield output folder
126 | [Ee]xpress/
127 |
128 | # DocProject is a documentation generator add-in
129 | DocProject/buildhelp/
130 | DocProject/Help/*.HxT
131 | DocProject/Help/*.HxC
132 | DocProject/Help/*.hhc
133 | DocProject/Help/*.hhk
134 | DocProject/Help/*.hhp
135 | DocProject/Help/Html2
136 | DocProject/Help/html
137 |
138 | # Click-Once directory
139 | publish/
140 |
141 | # Publish Web Output
142 | *.[Pp]ublish.xml
143 | *.azurePubxml
144 | # TODO: Comment the next line if you want to checkin your web deploy settings
145 | # but database connection strings (with potential passwords) will be unencrypted
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
150 | # checkin your Azure Web App publish settings, but sensitive information contained
151 | # in these scripts will be unencrypted
152 | PublishScripts/
153 |
154 | # NuGet Packages
155 | *.nupkg
156 | # The packages folder can be ignored because of Package Restore
157 | **/packages/*
158 | # except build/, which is used as an MSBuild target.
159 | !**/packages/build/
160 | # Uncomment if necessary however generally it will be regenerated when needed
161 | #!**/packages/repositories.config
162 | # NuGet v3's project.json files produces more ignoreable files
163 | *.nuget.props
164 | *.nuget.targets
165 |
166 | # Microsoft Azure Build Output
167 | csx/
168 | *.build.csdef
169 |
170 | # Microsoft Azure Emulator
171 | ecf/
172 | rcf/
173 |
174 | # Windows Store app package directories and files
175 | AppPackages/
176 | BundleArtifacts/
177 | Package.StoreAssociation.xml
178 | _pkginfo.txt
179 |
180 | # Visual Studio cache files
181 | # files ending in .cache can be ignored
182 | *.[Cc]ache
183 | # but keep track of directories ending in .cache
184 | !*.[Cc]ache/
185 |
186 | # Others
187 | ClientBin/
188 | ~$*
189 | *~
190 | *.dbmdl
191 | *.dbproj.schemaview
192 | *.jfm
193 | *.pfx
194 | *.publishsettings
195 | node_modules/
196 | orleans.codegen.cs
197 |
198 | # Since there are multiple workflows, uncomment next line to ignore bower_components
199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
200 | #bower_components/
201 |
202 | # RIA/Silverlight projects
203 | Generated_Code/
204 |
205 | # Backup & report files from converting an old project file
206 | # to a newer Visual Studio version. Backup files are not needed,
207 | # because we have git ;-)
208 | _UpgradeReport_Files/
209 | Backup*/
210 | UpgradeLog*.XML
211 | UpgradeLog*.htm
212 |
213 | # SQL Server files
214 | *.mdf
215 | *.ldf
216 |
217 | # Business Intelligence projects
218 | *.rdl.data
219 | *.bim.layout
220 | *.bim_*.settings
221 |
222 | # Microsoft Fakes
223 | FakesAssemblies/
224 |
225 | # GhostDoc plugin setting file
226 | *.GhostDoc.xml
227 |
228 | # Node.js Tools for Visual Studio
229 | .ntvs_analysis.dat
230 |
231 | # Visual Studio 6 build log
232 | *.plg
233 |
234 | # Visual Studio 6 workspace options file
235 | *.opt
236 |
237 | # Visual Studio LightSwitch build output
238 | **/*.HTMLClient/GeneratedArtifacts
239 | **/*.DesktopClient/GeneratedArtifacts
240 | **/*.DesktopClient/ModelManifest.xml
241 | **/*.Server/GeneratedArtifacts
242 | **/*.Server/ModelManifest.xml
243 | _Pvt_Extensions
244 |
245 | # Paket dependency manager
246 | .paket/paket.exe
247 | paket-files/
248 |
249 | # FAKE - F# Make
250 | .fake/
251 |
252 | # JetBrains Rider
253 | .idea/
254 | *.sln.iml
255 |
256 | # CodeRush
257 | .cr/
258 |
259 | # Python Tools for Visual Studio (PTVS)
260 | __pycache__/
261 | *.pyc
--------------------------------------------------------------------------------
/Enbiso.NLib.Cqrs.Idempotent/Enbiso.NLib.Cqrs.Idempotent.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | Enbiso.NLib.Cqrs.Idempotent
6 |
7 | 0.0.1-local
8 | $(PACKAGE_VERSION)
9 |
10 | enbiso
11 | Faraj Farook
12 | Simple Idempotent CQRS
13 | $(PACKAGE_COPYRIGHT)
14 | Enbiso Enbiso.NLib CQRS Idempotent
15 | true
16 | en-AU
17 | enbiso
18 | Initial Release
19 | Enbiso - Simple Idempotent CQRS .NET Standard
20 | Simple Idempotent CQRS
21 | logo.png
22 | $(PACKAGE_PROJECT)
23 | $(PACKAGE_REPO)
24 | default
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/Enbiso.NLib.Cqrs.Idempotent/IdempotentCommandBus.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text.Json;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using Enbiso.NLib.Idempotency;
6 |
7 | namespace Enbiso.NLib.Cqrs.Idempotent
8 | {
9 | ///
10 | /// Idempotent Command bus
11 | ///
12 | public interface IIdempotentCommandBus
13 | {
14 | Task Send(ICommand command, string requestId,
15 | CancellationToken cancellationToken = default(CancellationToken))
16 | where TResponse : ICommandResponse;
17 | }
18 |
19 | ///
20 | ///
21 | /// Idempotent Command bus implementation
22 | ///
23 | public class IdempotentCommandBus: IIdempotentCommandBus
24 | {
25 | private readonly ICommandBus _bus;
26 | private readonly IRequestManager _requestManager;
27 |
28 | public IdempotentCommandBus(ICommandBus bus, IRequestManager requestManager)
29 | {
30 | _bus = bus;
31 | _requestManager = requestManager;
32 | }
33 |
34 | public async Task Send(ICommand command, string requestId, CancellationToken cancellationToken = default(CancellationToken))
35 | where TResponse : ICommandResponse
36 | {
37 | if (!Guid.TryParse(requestId, out var reqGuid))
38 | throw new InvalidRequestIdException(requestId);
39 |
40 | var reqLog = await _requestManager.FindAsync(reqGuid);
41 | if (reqLog != null)
42 | {
43 | return JsonSerializer.Deserialize(reqLog.Response);
44 | }
45 | var response = await _bus.Send(command, cancellationToken);
46 | await _requestManager.CreateRequestAsync(reqGuid, command.GetType().Name, JsonSerializer.Serialize(response));
47 | return response;
48 | }
49 | }
50 |
51 | ///
52 | /// Invalid request ID exception
53 | ///
54 | public class InvalidRequestIdException : Exception
55 | {
56 | public string RequestId { get; private set; }
57 | public InvalidRequestIdException(string requestId) : base($"Error parsing request ID")
58 | {
59 | RequestId = requestId;
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/Enbiso.NLib.Cqrs.Idempotent/ServiceExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using Enbiso.NLib.Idempotency;
3 | using Microsoft.Extensions.DependencyInjection;
4 |
5 | namespace Enbiso.NLib.Cqrs.Idempotent
6 | {
7 | public static class ServiceExtensions
8 | {
9 | public static IServiceCollection AddCqrsIdempotent(this IServiceCollection services, bool autoLoadHandlers = true)
10 | {
11 | if (autoLoadHandlers) return services.AddCqrsIdempotent(Assembly.GetCallingAssembly());
12 | return services.AddCqrsIdempotent(new Assembly[0]);
13 | }
14 |
15 | public static IServiceCollection AddCqrsIdempotent(this IServiceCollection services,
16 | params Assembly[] assemblies)
17 | {
18 | services.AddIdempotency();
19 | services.AddCqrs(assemblies);
20 | services.AddScoped();
21 | return services;
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.Cqrs/Command.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 | using MediatR;
4 | using MediatR.Pipeline;
5 |
6 | namespace Enbiso.NLib.Cqrs
7 | {
8 | public interface IBaseCommand
9 | {
10 | }
11 |
12 | public interface ICommand: IRequest, IBaseCommand where TResponse: ICommandResponse
13 | {
14 | }
15 |
16 | public interface ICommandResponse
17 | {
18 |
19 | }
20 |
21 | public interface ICommandHandler : IRequestHandler
22 | where TCommand : ICommand
23 | where TResponse: ICommandResponse
24 | {
25 |
26 | }
27 |
28 | public interface ICommandPreProcessor
29 | where TCommand : ICommand
30 | where TResponse: ICommandResponse
31 | {
32 | Task Process(TCommand request, CancellationToken cancellationToken);
33 | }
34 |
35 | public interface ICommandPostProcessor
36 | where TCommand : ICommand
37 | where TResponse : ICommandResponse
38 | {
39 | Task Process(TCommand request, TResponse response, CancellationToken cancellationToken);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Enbiso.NLib.Cqrs/CommandBus.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 | using MediatR;
4 |
5 | namespace Enbiso.NLib.Cqrs
6 | {
7 | public interface ICommandBus
8 | {
9 | Task Send(ICommand command, CancellationToken cancellationToken = default)
10 | where TResponse : ICommandResponse;
11 | }
12 |
13 | public class CommandBus : ICommandBus
14 | {
15 | private readonly IMediator _mediator;
16 |
17 | public CommandBus(IMediator mediator)
18 | {
19 | _mediator = mediator;
20 | }
21 |
22 | public Task Send(ICommand command, CancellationToken cancellationToken = default)
23 | where TResponse : ICommandResponse
24 | {
25 | command = command ?? throw new CommandValidationException("Request command is empty");
26 | return _mediator.Send(command, cancellationToken);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Enbiso.NLib.Cqrs/CommandLogger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using MediatR;
5 | using Microsoft.Extensions.Logging;
6 |
7 | namespace Enbiso.NLib.Cqrs
8 | {
9 | public class LoggingBehavior : IPipelineBehavior
10 | where TCommand : ICommand
11 | where TResponse : ICommandResponse
12 | {
13 | private readonly ILogger> _logger;
14 |
15 | public LoggingBehavior(ILogger> logger)
16 | {
17 | _logger = logger;
18 | }
19 |
20 | public async Task Handle(TCommand request, RequestHandlerDelegate next,
21 | CancellationToken cancellationToken)
22 | {
23 | try
24 | {
25 | _logger.LogTrace("Handling {Name}", typeof(TCommand).Name);
26 | var response = await next();
27 | _logger.LogTrace("Handled {Name}", typeof(TCommand).Name);
28 | return response;
29 | }
30 | catch (Exception e)
31 | {
32 | _logger.LogError(e, "Failed {Name}", typeof(TResponse).Name);
33 | throw;
34 | }
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.Cqrs/CommandProcessor.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using MediatR;
6 |
7 | namespace Enbiso.NLib.Cqrs
8 | {
9 | public class ProcessorBehaviour: IPipelineBehavior
10 | where TCommand : ICommand
11 | where TResponse : ICommandResponse
12 | {
13 | private readonly IEnumerable> _preProcessors;
14 | private readonly IEnumerable> _postProcessors;
15 |
16 | public ProcessorBehaviour(IEnumerable> preProcessors,
17 | IEnumerable> postProcessors)
18 | {
19 | _preProcessors = preProcessors;
20 | _postProcessors = postProcessors;
21 | }
22 |
23 | public async Task Handle(TCommand request, RequestHandlerDelegate next, CancellationToken cancellationToken)
24 | {
25 | await Task.WhenAll(
26 | _preProcessors.Select(p => p.Process(request, cancellationToken)));
27 |
28 | var response = await next();
29 |
30 | await Task.WhenAll(
31 | _postProcessors.Select(p => p.Process(request, response, cancellationToken)));
32 |
33 | return response;
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.Cqrs/CommandValidator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 | using MediatR;
7 |
8 | namespace Enbiso.NLib.Cqrs
9 | {
10 | public class ValidatorBehavior : IPipelineBehavior
11 | where TCommand : ICommand
12 | where TResponse : ICommandResponse
13 | {
14 | private readonly IEnumerable> _validators;
15 |
16 | public ValidatorBehavior(IEnumerable> validators)
17 | {
18 | _validators = validators;
19 | }
20 |
21 | public async Task Handle(TCommand request,
22 | RequestHandlerDelegate next, CancellationToken cancellationToken)
23 | {
24 | var validatorTasks = _validators.Select(v => v.Validate(request)).ToArray();
25 | await Task.WhenAll(validatorTasks);
26 | var failures = validatorTasks.SelectMany(t => t.Result).Where(error => error != null).ToArray();
27 |
28 | if (failures.Any())
29 | throw new CommandValidationException(typeof(TCommand), failures);
30 |
31 | var response = await next();
32 | return response;
33 | }
34 | }
35 |
36 | ///
37 | /// Command validator
38 | ///
39 | ///
40 | public interface ICommandValidator
41 | where TCommand: IBaseCommand
42 | {
43 | Task> Validate(TCommand command);
44 | }
45 |
46 | ///
47 | /// Validation ValidationError
48 | ///
49 | public class ValidationError
50 | {
51 | public string Message { get; }
52 | public string Property { get; }
53 |
54 | public ValidationError(string message, string property)
55 | {
56 | Message = message;
57 | Property = property;
58 | }
59 | }
60 |
61 | ///
62 | /// Command Validation exception
63 | ///
64 | public class CommandValidationException : Exception
65 | {
66 | public IEnumerable Errors { get; }
67 | public CommandValidationException(Type command, IEnumerable failures = null)
68 | : this($"{command.Name} validation failed")
69 | {
70 | Errors = failures;
71 | }
72 | public CommandValidationException(string message): base(message) {
73 |
74 | }
75 | }
76 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.Cqrs/Enbiso.NLib.Cqrs.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | Enbiso.NLib.Cqrs
6 |
7 | 0.0.1-local
8 | $(PACKAGE_VERSION)
9 |
10 | enbiso
11 | Faraj Farook
12 | Simple CQRS
13 | $(PACKAGE_COPYRIGHT)
14 | Enbiso Enbiso.NLib CQRS
15 | true
16 | en-AU
17 | enbiso
18 | Initial Release
19 | Enbiso - Simple CQRS .NET Standard
20 | Simple CQRS
21 | logo.png
22 | $(PACKAGE_PROJECT)
23 | $(PACKAGE_REPO)
24 | default
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/Enbiso.NLib.Cqrs/IQuery.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading.Tasks;
3 |
4 | namespace Enbiso.NLib.Cqrs
5 | {
6 | public interface IQuery
7 | where TQueryModel : IQueryModel
8 | where TSummeryQueryModel : ISummaryQueryModel
9 | {
10 | Task GetByIdAsync(TKey key);
11 | Task> ListAsync(TSearch search);
12 | }
13 |
14 | public interface IQuery : IQuery
15 | {
16 | }
17 |
18 | public interface IQueryModel
19 | {
20 | }
21 |
22 | public interface ISummaryQueryModel
23 | {
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Enbiso.NLib.Cqrs/ServiceExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Reflection;
4 | using MediatR;
5 | using MediatR.Pipeline;
6 | using Microsoft.Extensions.DependencyInjection;
7 |
8 | namespace Enbiso.NLib.Cqrs
9 | {
10 | public static class ServiceExtensions
11 | {
12 | public static IServiceCollection AddCqrs(this IServiceCollection services, bool autoLoadHandlers = true)
13 | {
14 | if (!autoLoadHandlers) return services.AddCqrs(new Assembly[0]);
15 | return services.AddCqrs(Assembly.GetCallingAssembly());
16 | }
17 |
18 | public static IServiceCollection AddCqrs(this IServiceCollection services, params Assembly[] assemblies)
19 | {
20 | if (services.All(s => s.ServiceType != typeof(IMediator)))
21 | services.AddMediatR(assemblies);
22 |
23 | services.AddScoped();
24 | services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
25 | services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidatorBehavior<,>));
26 | services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ProcessorBehaviour<,>));
27 | return services;
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.DependencyInjection/Enbiso.NLib.DependencyInjection.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | Enbiso.NLib.DependencyInjection
6 |
7 | 0.0.1-local
8 | $(PACKAGE_VERSION)
9 |
10 | enbiso
11 | Faraj Farook
12 | Simple Annotated Dependency Injection library
13 | $(PACKAGE_COPYRIGHT)
14 | Enbiso Enbiso.NLib Annotated Dependency Injection
15 | true
16 | en-AU
17 | enbiso
18 | Initial Release
19 | Enbiso - Simple Annotated Dependency Injection in .NET Standard
20 | Annotated Dependency Injection
21 |
22 | logo.png
23 | $(PACKAGE_PROJECT)
24 | $(PACKAGE_REPO)
25 | default
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/Enbiso.NLib.DependencyInjection/ServiceAttributes.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.Extensions.DependencyInjection;
3 |
4 | namespace Enbiso.NLib.DependencyInjection
5 | {
6 | public abstract class ServiceAttribute : Attribute
7 | {
8 | public ServiceLifetime Lifetime { get; }
9 | public Type[] ServiceTypes { get; }
10 |
11 | protected ServiceAttribute(ServiceLifetime lifetime, params Type[] serviceTypes)
12 | {
13 | Lifetime = lifetime;
14 | ServiceTypes = serviceTypes;
15 | }
16 | }
17 |
18 | ///
19 | /// Add as Transient ServiceTypes
20 | ///
21 | [AttributeUsage(AttributeTargets.Class)]
22 | public class TransientServiceAttribute : ServiceAttribute
23 | {
24 | public TransientServiceAttribute(params Type[] serviceTypes) : base(ServiceLifetime.Transient, serviceTypes)
25 | {
26 | }
27 | }
28 |
29 | ///
30 | /// Add as Scoped ServiceTypes
31 | ///
32 |
33 | [AttributeUsage(AttributeTargets.Class)]
34 | public class ScopedServiceAttribute : ServiceAttribute
35 | {
36 | public ScopedServiceAttribute(params Type[] serviceTypes) : base(ServiceLifetime.Scoped, serviceTypes)
37 | {
38 | }
39 | }
40 |
41 | ///
42 | /// Add as Singleton ServiceTypes
43 | ///
44 | [AttributeUsage(AttributeTargets.Class)]
45 | public class SingletonServiceAttribute : ServiceAttribute
46 | {
47 | public SingletonServiceAttribute(params Type[] serviceTypes) : base(ServiceLifetime.Singleton, serviceTypes)
48 | {
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Enbiso.NLib.DependencyInjection/ServiceExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using Microsoft.Extensions.DependencyInjection;
6 |
7 | namespace Enbiso.NLib.DependencyInjection
8 | {
9 | public static class ServiceExtensions
10 | {
11 | public static IServiceCollection AddServices(this IServiceCollection services, params Type[] typeReferences)
12 | {
13 | return services.AddServices(typeReferences.Select(t => t.Assembly).ToArray());
14 | }
15 |
16 | public static IServiceCollection AddServices(this IServiceCollection services, params Assembly[] assemblies)
17 | {
18 | assemblies.ToList().ForEach(services.AddServicesForAssembly);
19 | return services;
20 | }
21 |
22 | public static IServiceCollection AddServices(this IServiceCollection services)
23 | {
24 | var entry = Assembly.GetEntryAssembly();
25 | var assemblies = entry.GetReferencedAssemblies().Select(Assembly.Load).ToList();
26 | assemblies.Add(entry);
27 | return services.AddServices(assemblies.ToArray());
28 | }
29 |
30 | private static void AddServicesForAssembly(this IServiceCollection services, Assembly assembly)
31 | {
32 | foreach (var type in assembly.GetTypes())
33 | {
34 | var service = type.GetCustomAttribute();
35 | if (service == null) continue;
36 | // Get defined interfaces
37 | var interfaces = service.ServiceTypes.ToList();
38 | // If not specified add implemented interfaces
39 | if (!interfaces.Any()) interfaces.AddRange(type.GetInterfaces());
40 | // If not then self bind
41 | if (!interfaces.Any()) interfaces.Add(type);
42 |
43 | switch (service.Lifetime)
44 | {
45 | case ServiceLifetime.Transient:
46 | interfaces.ForEach(@interface => services.AddTransient(@interface, type));
47 | break;
48 | case ServiceLifetime.Singleton:
49 | interfaces.ForEach(@interface => services.AddSingleton(@interface, type));
50 | break;
51 | case ServiceLifetime.Scoped:
52 | interfaces.ForEach(@interface => services.AddScoped(@interface, type));
53 | break;
54 | default:
55 | throw new Exception("Unknown scope specified");
56 | }
57 | }
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Enbiso.NLib.Domain.Events/DomainEvent.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 |
3 | namespace Enbiso.NLib.Domain.Events
4 | {
5 | ///
6 | /// Domain event
7 | ///
8 | public interface IDomainEvent: INotification, IEntityEvent
9 | {
10 | }
11 |
12 | ///
13 | /// Domain event handlers
14 | ///
15 | ///
16 | public interface IDomainEventHandler: INotificationHandler
17 | where TDomainEvent: IDomainEvent
18 | {
19 |
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Enbiso.NLib.Domain.Events/DomainEventBus.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using MediatR;
6 |
7 | namespace Enbiso.NLib.Domain.Events
8 | {
9 | ///
10 | /// Domain event bus
11 | ///
12 | public interface IDomainEventBus
13 | {
14 | Task Publish(TDomainEvent @event, CancellationToken cancellationToken = default(CancellationToken)) where TDomainEvent : IDomainEvent;
15 | Task[] PublishFromEntities(IEnumerable entities, CancellationToken cancellationToken = default(CancellationToken));
16 | }
17 |
18 | ///
19 | /// Domain event bus implementation
20 | ///
21 | public class DomainEventBus: IDomainEventBus
22 | {
23 | private readonly IMediator _mediator;
24 |
25 | public DomainEventBus(IMediator mediator)
26 | {
27 | _mediator = mediator;
28 | }
29 |
30 | public Task Publish(TDomainEvent @event, CancellationToken cancellationToken = default(CancellationToken)) where TDomainEvent : IDomainEvent
31 | {
32 | return _mediator.Publish(@event, cancellationToken);
33 | }
34 |
35 | public Task[] PublishFromEntities(IEnumerable entities,
36 | CancellationToken cancellationToken = default(CancellationToken))
37 | {
38 | return entities.GetEvents().Select(async e => await Publish(e, cancellationToken)).ToArray();
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Enbiso.NLib.Domain.Events/Enbiso.NLib.Domain.Events.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | Enbiso.NLib.Domain.Events
6 |
7 | 0.0.1-local
8 | $(PACKAGE_VERSION)
9 |
10 | enbiso
11 | Faraj Farook
12 | Simple domain event library
13 | $(PACKAGE_COPYRIGHT)
14 | Enbiso Enbiso.NLib Domain Event
15 | true
16 | en-AU
17 | enbiso
18 | Initial Release
19 | Enbiso - Simple Domain event in .NET Standard
20 | Simple Domain Event
21 | logo.png
22 | $(PACKAGE_PROJECT)
23 | $(PACKAGE_REPO)
24 | default
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/Enbiso.NLib.Domain.Events/ServiceExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Reflection;
4 | using MediatR;
5 | using Microsoft.Extensions.DependencyInjection;
6 |
7 | namespace Enbiso.NLib.Domain.Events
8 | {
9 | public static class ServiceExtensions
10 | {
11 | public static IServiceCollection AddDomainEvents(this IServiceCollection services)
12 | {
13 | var assembly = Assembly.GetCallingAssembly();
14 | return services.AddDomainEvents(assembly);
15 | }
16 |
17 | public static IServiceCollection AddDomainEvents(this IServiceCollection services, params Assembly[] assemblies)
18 | {
19 | if (services.All(s => s.ServiceType != typeof(IMediator)))
20 | services.AddMediatR(assemblies);
21 |
22 | services.AddScoped();
23 | return services;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Enbiso.NLib.Domain/Enbiso.NLib.Domain.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | Enbiso.NLib.Domain
6 |
7 | 0.0.1-local
8 | $(PACKAGE_VERSION)
9 |
10 | enbiso
11 | Faraj Farook
12 | Simple domain SeedWork library
13 | $(PACKAGE_COPYRIGHT)
14 | Enbiso Enbiso.NLib Domain SeedWork
15 | true
16 | en-AU
17 | enbiso
18 | Initial Release
19 | Enbiso - Simple Domain SeedWorks in .NET Standard
20 | Simple Domain Seedwork
21 | logo.png
22 | $(PACKAGE_PROJECT)
23 | $(PACKAGE_REPO)
24 | default
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Enbiso.NLib.Domain/Entity.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | namespace Enbiso.NLib.Domain
6 | {
7 | ///
8 | /// Aggregated root entity
9 | ///
10 | public interface IRootEntity
11 | {
12 | }
13 |
14 | ///
15 | /// Base Event
16 | ///
17 | public interface IEntityEvent
18 | {
19 | }
20 |
21 | ///
22 | /// Domain Entity interface
23 | ///
24 | public interface IEntity
25 | {
26 | List GetEvents();
27 | }
28 |
29 | public abstract class Entity: IEntity
30 | {
31 | private readonly List _events = new List();
32 |
33 | public void AddEvent(IEntityEvent @event)
34 | {
35 | _events.Add(@event?? throw new ArgumentNullException());
36 | }
37 |
38 | public void RemoveEvent(IEntityEvent @event)
39 | {
40 | _events.Remove(@event ?? throw new ArgumentNullException());
41 | }
42 |
43 | public List GetEvents() => _events;
44 | }
45 |
46 | ///
47 | ///
48 | /// Domain Entity abstraction
49 | ///
50 | ///
51 | public abstract class Entity: Entity
52 | {
53 | private int? _requestedHashCode;
54 | public virtual TKey Id { get; set; }
55 |
56 | public bool IsTransient()
57 | {
58 | return default(TKey)?.Equals(Id) ?? true;
59 | }
60 |
61 | public override bool Equals(object obj)
62 | {
63 | if (!(obj is Entity))
64 | return false;
65 |
66 | if (ReferenceEquals(this, obj))
67 | return true;
68 |
69 | if (GetType() != obj.GetType())
70 | return false;
71 |
72 | var item = (Entity)obj;
73 |
74 | if (item.IsTransient() || IsTransient())
75 | return false;
76 |
77 | return item.Id?.Equals(Id) ?? false;
78 | }
79 |
80 | public override int GetHashCode()
81 | {
82 | if (IsTransient()) return base.GetHashCode();
83 |
84 | if (!_requestedHashCode.HasValue)
85 | _requestedHashCode = Id.GetHashCode() ^ 31;
86 |
87 | return _requestedHashCode.Value;
88 | }
89 |
90 | public static bool operator ==(Entity left, Entity right)
91 | {
92 | return left?.Equals(right) ?? Equals(right, null);
93 | }
94 |
95 | public static bool operator !=(Entity left, Entity right)
96 | {
97 | return !(left == right);
98 | }
99 | }
100 |
101 | ///
102 | /// Entity helper extensions
103 | ///
104 | public static class EntityExtensions
105 | {
106 | public static void ClearEvents(this IEnumerable entities)
107 | {
108 | foreach (var entity in entities)
109 | {
110 | entity.GetEvents().Clear();
111 | }
112 | }
113 |
114 | public static IEnumerable GetEvents(this IEnumerable entities) where TEvent: IEntityEvent
115 | {
116 | return entities.ToList().SelectMany(e => e.GetEvents()).OfType();
117 | }
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/Enbiso.NLib.Domain/Exception.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Enbiso.NLib.Domain
4 | {
5 | ///
6 | ///
7 | /// Domain Exception
8 | ///
9 | public class DomainException: Exception
10 | {
11 | public DomainException()
12 | {
13 | }
14 |
15 | public DomainException(string message) : base(message)
16 | {
17 | }
18 |
19 | public DomainException(string message, Exception innerException) : base(message, innerException)
20 | {
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.Domain/Repository.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 |
5 | namespace Enbiso.NLib.Domain
6 | {
7 | ///
8 | ///
9 | /// Repository
10 | ///
11 | ///
12 | public interface IRepository : IRepository where T : IRootEntity
13 | {
14 | }
15 |
16 | ///
17 | /// Repository
18 | ///
19 | public interface IRepository
20 | {
21 | IUnitOfWork UnitOfWork { get; }
22 | }
23 |
24 | ///
25 | ///
26 | /// Unit of work
27 | ///
28 | public interface IUnitOfWork : IDisposable
29 | {
30 | Task SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken));
31 | Task SaveEntitiesAsync(CancellationToken cancellationToken = default(CancellationToken));
32 | }
33 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.Abstractions/Enbiso.NLib.EventBus.Abstractions.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | Enbiso.NLib.EventBus.Abstractions
6 | Enbiso.NLib.EventBus
7 | 0.0.1-local
8 | $(PACKAGE_VERSION)
9 | Faraj Farook
10 | Simple Abstract event bus library
11 | false
12 | $(PACKAGE_COPYRIGHT)
13 | Enbiso Enbiso.NLib EventBus
14 | true
15 | en-AU
16 | enbiso
17 | Initial Release
18 | Enbiso - Simple Abstract EventBus Library in .NET Standard
19 | Simple Abstract EventBus
20 | logo.png
21 | $(PACKAGE_PROJECT)
22 | $(PACKAGE_REPO)
23 | default
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.Abstractions/IEvent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Enbiso.NLib.EventBus
4 | {
5 | public interface IEvent
6 | {
7 | Guid EventId { get; }
8 | DateTime EventCreationDate { get; }
9 | }
10 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.Abstractions/IEventHandler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 |
4 | namespace Enbiso.NLib.EventBus
5 | {
6 | ///
7 | /// Integration event handler
8 | ///
9 | public interface IEventHandler
10 | {
11 | bool IsValidFor(string eventName);
12 | Type EventType { get; }
13 | Task Handle(object @event);
14 | }
15 |
16 | ///
17 | /// Abstract event handler
18 | ///
19 | ///
20 | public abstract class EventHandler: IEventHandler where TEvent : class, IEvent
21 | {
22 | protected abstract Task Handle(TEvent @event);
23 | public Type EventType => typeof(TEvent);
24 | public Task Handle(object @event) => Handle(@event as TEvent);
25 | public bool IsValidFor(string eventName) => eventName == "*" || eventName == EventType.Name;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.Abstractions/IEventPublisher.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace Enbiso.NLib.EventBus
5 | {
6 | public interface IEventPublisher
7 | {
8 | ///
9 | /// Publish @event
10 | ///
11 | ///
12 | ///
13 | ///
14 | ///
15 | Task Publish(TEvent @event, string exchange, string eventType, CancellationToken cancellationToken) where TEvent : IEvent;
16 | }
17 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.Abstractions/IEventService.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace Enbiso.NLib.EventBus
5 | {
6 | public interface IEventService
7 | {
8 | ///
9 | /// Publish to bus
10 | ///
11 | ///
12 | ///
13 | ///
14 | ///
15 | ///
16 | ///
17 | Task PublishToBus(T @event, string exchange = null, string eventType = null,
18 | CancellationToken token = default) where T : IEvent;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.Abstractions/IEventSubscriber.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 |
5 | namespace Enbiso.NLib.EventBus
6 | {
7 | ///
8 | /// Event bus interface
9 | ///
10 | public interface IEventSubscriber: IDisposable
11 | {
12 | ///
13 | /// Subscribe to all events
14 | ///
15 | /// Cancellation Token
16 | ///
17 | Task Subscribe(CancellationToken token = default);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.Abstractions/IEventSubscriptionService.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace Enbiso.NLib.EventBus
5 | {
6 | public interface IEventSubscriptionService
7 | {
8 | ///
9 | /// Subscribe all event processors
10 | ///
11 | ///
12 | Task SubscribeAll(CancellationToken token = default);
13 | }
14 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.AwsSns/AwsSnsConnection.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Runtime.InteropServices.ComTypes;
3 | using System.Threading.Tasks;
4 | using Amazon.SimpleNotificationService;
5 | using Amazon.SimpleNotificationService.Model;
6 |
7 | namespace Enbiso.NLib.EventBus.AwsSns
8 | {
9 | public interface IAwsSnsConnection
10 | {
11 | IAmazonSimpleNotificationService GetConnection();
12 | Task GetTopic(string exchangeName);
13 | }
14 |
15 | public class AwsSnsConnection: IAwsSnsConnection
16 | {
17 | private readonly IAmazonSimpleNotificationService _connection;
18 | private readonly Dictionary _topics = new();
19 |
20 | public AwsSnsConnection(IAmazonSimpleNotificationService connection)
21 | {
22 | _connection = connection;
23 | }
24 |
25 | public IAmazonSimpleNotificationService GetConnection() => _connection;
26 |
27 | public async Task GetTopic(string exchangeName)
28 | {
29 | if (_topics.TryGetValue(exchangeName, out var existingTopic))
30 | return existingTopic;
31 | var topic = await _connection.FindTopicAsync(exchangeName);
32 | if (topic == null)
33 | {
34 | await _connection.CreateTopicAsync(exchangeName);
35 | topic = await _connection.FindTopicAsync(exchangeName);
36 | }
37 |
38 | lock (_topics)
39 | {
40 | _topics[exchangeName] = topic;
41 | }
42 | return topic;
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.AwsSns/AwsSnsEventPublisher.cs:
--------------------------------------------------------------------------------
1 | using System.Text.Json;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using Amazon.SimpleNotificationService.Model;
5 | using Microsoft.Extensions.Options;
6 |
7 | namespace Enbiso.NLib.EventBus.AwsSns
8 | {
9 | public class AwsSnsEventPublisher: IEventPublisher
10 | {
11 | private readonly IAwsSnsConnection _connection;
12 | private readonly AwsSnsOptions _options;
13 |
14 | public AwsSnsEventPublisher(IAwsSnsConnection connection, IOptions options)
15 | {
16 | _connection = connection;
17 | _options = options.Value;
18 | }
19 |
20 | public async Task Publish(TEvent @event, string exchange, string eventType, CancellationToken cancellationToken) where TEvent : IEvent
21 | {
22 | exchange ??= _options.PublishExchange;
23 | exchange = exchange?.Replace(".", "-");
24 | var topic = await _connection.GetTopic(exchange);
25 |
26 | eventType ??= @event.GetType().Name;
27 | var message = JsonSerializer.Serialize(@event);
28 |
29 | var request = new PublishRequest(topic.TopicArn, message, eventType)
30 | {
31 | MessageAttributes =
32 | {
33 | ["EventType"] = new MessageAttributeValue {DataType = "String", StringValue = eventType}
34 | }
35 | };
36 |
37 | await _connection.GetConnection().PublishAsync(request, cancellationToken);
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.AwsSns/AwsSnsEventSubscriber.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace Enbiso.NLib.EventBus.AwsSns
5 | {
6 | public class AwsSnsEventSubscriber: IEventSubscriber
7 | {
8 | public void Dispose()
9 | {
10 | }
11 |
12 | public Task Subscribe(CancellationToken token = default)
13 | {
14 | return Task.CompletedTask;
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.AwsSns/AwsSnsOptions.cs:
--------------------------------------------------------------------------------
1 | namespace Enbiso.NLib.EventBus.AwsSns
2 | {
3 | public class AwsSnsOptions
4 | {
5 | public string PublishExchange { get; set; }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.AwsSns/Enbiso.NLib.EventBus.AwsSns.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | Enbiso.NLib.EventBus.AwsSns
6 |
7 | 0.0.1-local
8 | $(PACKAGE_VERSION)
9 |
10 | Faraj Farook
11 | Simple Event bus implementation for AWS SNS
12 | false
13 | $(PACKAGE_COPYRIGHT)
14 | Enbiso Enbiso.NLib EventBus NATS
15 | true
16 | en-AU
17 | enbiso
18 | Initial Release
19 | Enbiso - SSimple Event bus implementation for AWS SNS in .NET Standard
20 | Simple AWS SNS EventBus
21 |
22 | logo.png
23 | $(PACKAGE_PROJECT)
24 | $(PACKAGE_REPO)
25 | default
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.AwsSns/ServiceExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Amazon.SimpleNotificationService;
3 | using Microsoft.Extensions.DependencyInjection;
4 |
5 | namespace Enbiso.NLib.EventBus.AwsSns
6 | {
7 | public static class ServiceExtensions
8 | {
9 | ///
10 | /// Add Event bus with default connection and manager
11 | ///
12 | ///
13 | ///
14 | public static void AddEventBusAwsSns(this IServiceCollection services, Action option)
15 | {
16 | services.Configure(option);
17 |
18 | services.AddEventBus();
19 | services.AddSingleton();
20 | services.AddSingleton();
21 | services.AddSingleton();
22 | services.AddSingleton();
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.Nats/Enbiso.NLib.EventBus.Nats.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | Enbiso.NLib.EventBus.Nats
6 |
7 | 0.0.1-local
8 | $(PACKAGE_VERSION)
9 |
10 | Faraj Farook
11 | Simple Event bus implementation for NATs
12 | false
13 | $(PACKAGE_COPYRIGHT)
14 | Enbiso Enbiso.NLib EventBus NATS
15 | true
16 | en-AU
17 | enbiso
18 | Initial Release
19 | Enbiso - Simple Event bus implementation for NATs in .NET Standard
20 | Simple NATs EventBus
21 |
22 | logo.png
23 | $(PACKAGE_PROJECT)
24 | $(PACKAGE_REPO)
25 | default
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.Nats/JetStream/JetStreamConnection.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.Extensions.Logging;
3 | using NATS.Client.JetStream;
4 |
5 | namespace Enbiso.NLib.EventBus.Nats.JetStream;
6 |
7 | public interface IJetStreamConnection: IDisposable
8 | {
9 | void VerifyJetStream(string streamName);
10 | public IJetStream GetJetStream();
11 |
12 | event ConnectedEventHandler Connected;
13 | }
14 |
15 | public class JetStreamConnection: IJetStreamConnection
16 | {
17 | private IJetStreamManagement _jetStreamManagement;
18 | private IJetStream _jetStream;
19 | private readonly INatsConnection _connection;
20 |
21 | public event ConnectedEventHandler Connected;
22 |
23 | public JetStreamConnection(INatsConnection connection, ILogger logger)
24 | {
25 | _connection = connection;
26 | connection.Connected += conn =>
27 | {
28 | _jetStreamManagement = conn.CreateJetStreamManagementContext();
29 | _jetStream = conn.CreateJetStreamContext();
30 | logger.LogInformation("JetStream Initialised");
31 |
32 | Connected?.Invoke(conn);
33 | };
34 | }
35 |
36 | public void VerifyJetStream(string streamName)
37 | {
38 | _connection.VerifyConnection();
39 |
40 | var streamNames = _jetStreamManagement.GetStreamNames();
41 | if (streamNames.Contains(streamName)) return;
42 |
43 | var sc = StreamConfiguration.Builder()
44 | .WithName(streamName)
45 | .WithStorageType(StorageType.Memory)
46 | .WithRetentionPolicy(RetentionPolicy.Interest) //wait for all consumers
47 | .WithSubjects($"{streamName}.>")
48 | .Build();
49 | _jetStreamManagement.AddStream(sc);
50 | }
51 |
52 | public IJetStream GetJetStream() => _jetStream;
53 |
54 |
55 | public void Dispose()
56 | {
57 | _connection?.Dispose();
58 | }
59 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.Nats/JetStream/JetStreamEventPublisher.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using System.Text.Json;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using Microsoft.Extensions.Logging;
6 | using Microsoft.Extensions.Options;
7 |
8 | namespace Enbiso.NLib.EventBus.Nats.JetStream
9 | {
10 | public class JetStreamEventPublisher: IEventPublisher
11 | {
12 | private readonly IJetStreamConnection _jetStreamConnection;
13 | private readonly NatsOptions _options;
14 | private readonly ILogger _logger;
15 |
16 | public JetStreamEventPublisher(IOptions options, ILogger logger, IJetStreamConnection jetStreamConnection)
17 | {
18 | _options = options.Value;
19 | _logger = logger;
20 | _jetStreamConnection = jetStreamConnection;
21 | }
22 |
23 | public Task Publish(TEvent @event, string exchange, string eventType, CancellationToken cancellationToken) where TEvent : IEvent
24 | {
25 | exchange ??= _options.PublishExchange ?? _options.Exchanges.FirstOrDefault();
26 |
27 | var eventPath = $"{exchange}.{eventType ?? @event.GetType().Name}";
28 | var body = JsonSerializer.SerializeToUtf8Bytes(@event);
29 |
30 | var policy = NatsPolicyBuilder.BuildPublishPolicy(_options.PublishRetryCount, _logger);
31 |
32 | _jetStreamConnection.VerifyJetStream(exchange);
33 | var js = _jetStreamConnection.GetJetStream();
34 |
35 | policy.Execute(() =>
36 | {
37 | js.PublishAsync(eventPath, body);
38 | });
39 |
40 | return Task.CompletedTask;
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.Nats/JetStream/JetStreamEventSubscriber.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using Microsoft.Extensions.Options;
5 | using NATS.Client.JetStream;
6 |
7 | namespace Enbiso.NLib.EventBus.Nats.JetStream
8 | {
9 | public class JetStreamEventSubscriber: IEventSubscriber
10 | {
11 | private readonly IJetStreamConnection _jsConnection;
12 | private readonly INatsConnection _natsConnection;
13 | private readonly IEventProcessor _eventProcessor;
14 | private readonly NatsOptions _options;
15 |
16 | public JetStreamEventSubscriber(IJetStreamConnection jsConnection, IOptions options,
17 | IEventProcessor eventProcessor, INatsConnection natsConnection)
18 | {
19 | _jsConnection = jsConnection;
20 | _eventProcessor = eventProcessor;
21 | _natsConnection = natsConnection;
22 | _options = options.Value;
23 | }
24 |
25 | public void Dispose()
26 | {
27 | _natsConnection?.Dispose();
28 | _jsConnection?.Dispose();
29 | }
30 |
31 | public Task Subscribe(CancellationToken token = default)
32 | {
33 | _jsConnection.Connected += _ =>
34 | {
35 | foreach (var exchange in _options.Exchanges ?? Array.Empty())
36 | {
37 | _jsConnection.VerifyJetStream(exchange);
38 |
39 | var js = _jsConnection.GetJetStream();
40 | var pullOptions = PullSubscribeOptions.Builder()
41 | .WithDurable($"{_options.Client}_{exchange}")
42 | .Build();
43 | var sub = js.PullSubscribe($"{exchange}.>", pullOptions);
44 |
45 | Task.Run(async () =>
46 | {
47 | while (!token.IsCancellationRequested)
48 | {
49 | foreach (var message in sub.Fetch(_options.PollBatchSize, _options.PollWaitMills))
50 | {
51 | var eventName = GetEventName(message.Subject, exchange);
52 | await _eventProcessor.ProcessEvent(eventName, message.Data);
53 | message.Ack();
54 | }
55 | }
56 | }, token);
57 | }
58 | };
59 | _natsConnection.VerifyConnection();
60 | return Task.CompletedTask;
61 | }
62 |
63 | private static string GetEventName(string subject, string exchange) =>
64 | subject.StartsWith(exchange)
65 | ? subject[(exchange.Length + 1)..]
66 | : subject;
67 | }
68 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.Nats/NatsConnection.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using Microsoft.Extensions.Logging;
5 | using Microsoft.Extensions.Options;
6 | using NATS.Client;
7 | using Options = NATS.Client.Options;
8 |
9 | namespace Enbiso.NLib.EventBus.Nats
10 | {
11 | public interface INatsConnection : IDisposable
12 | {
13 | IConnection GetConnection();
14 | void VerifyConnection();
15 | event ConnectedEventHandler Connected;
16 | }
17 |
18 | public delegate void ConnectedEventHandler(IConnection connection);
19 |
20 | public class NatsConnection: INatsConnection
21 | {
22 | private IConnection _connection;
23 | private readonly ConnectionFactory _factory;
24 | private readonly Options _opts;
25 | private readonly ILogger _logger;
26 | private bool _disposed;
27 | public event ConnectedEventHandler Connected;
28 |
29 | public NatsConnection(ConnectionFactory factory, IOptions options, ILogger logger)
30 | {
31 | _logger = logger;
32 | _factory = factory;
33 |
34 | var settings = options.Value;
35 | _opts = ConnectionFactory.GetDefaultOptions();
36 | _opts.Servers = settings.Servers;
37 |
38 | _opts.MaxReconnect = settings.RetryCount;
39 | if (!string.IsNullOrEmpty(settings.Username))
40 | _opts.User = settings.Username;
41 | if (!string.IsNullOrEmpty(settings.Password))
42 | _opts.Password = settings.Password;
43 | if (!string.IsNullOrEmpty(settings.Token))
44 | _opts.Token = settings.Token;
45 |
46 | _opts.DisconnectedEventHandler += (sender, args) =>
47 | {
48 | _logger.LogWarning("Connection to NATS disconnected. Trying to reconnect...");
49 | VerifyConnection();
50 | };
51 | }
52 |
53 | public IConnection GetConnection() => _connection;
54 |
55 | private bool IsConnected => _connection?.State == ConnState.CONNECTED && !_disposed;
56 | public void VerifyConnection()
57 | {
58 | if (IsConnected) return;
59 |
60 | var policy = NatsPolicyBuilder.BuildConnectPolicy(_logger);
61 |
62 | policy.Execute(() =>
63 | {
64 | var servers = _opts.Servers ?? Array.Empty();
65 | _logger.LogInformation("Connecting to {Servers}", string.Join(", ", servers));
66 | _connection = _factory.CreateConnection(_opts);
67 | if (!IsConnected) return;
68 | _logger.LogInformation("Connected to NATS");
69 | Connected?.Invoke(_connection);
70 | });
71 | }
72 |
73 |
74 |
75 | public void Dispose()
76 | {
77 | if (_disposed) return;
78 | _disposed = true;
79 | try
80 | {
81 | _connection.Drain();
82 | _connection.Close();
83 | _connection.Dispose();
84 | }
85 | catch (Exception ex)
86 | {
87 | _logger.LogCritical("{Error}",ex.ToString());
88 | }
89 | }
90 |
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.Nats/NatsEventPublisher.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using System.Text.Json;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using Microsoft.Extensions.Logging;
6 | using Microsoft.Extensions.Options;
7 |
8 | namespace Enbiso.NLib.EventBus.Nats;
9 |
10 | public class NatsEventPublisher: IEventPublisher
11 | {
12 | private readonly INatsConnection _connection;
13 | private readonly NatsOptions _options;
14 | private readonly ILogger _logger;
15 |
16 | public NatsEventPublisher(INatsConnection connection, IOptions options, ILogger logger)
17 | {
18 | _connection = connection;
19 | _options = options.Value;
20 | _logger = logger;
21 | }
22 |
23 | public Task Publish(TEvent @event, string exchange, string eventType, CancellationToken cancellationToken) where TEvent : IEvent
24 | {
25 | exchange ??= _options.PublishExchange ?? _options.Exchanges.FirstOrDefault();
26 |
27 | var eventPath = $"{exchange}.{eventType ?? @event.GetType().Name}";
28 | var body = JsonSerializer.SerializeToUtf8Bytes(@event);
29 |
30 | var policy = NatsPolicyBuilder.BuildPublishPolicy(_options.PublishRetryCount, _logger);
31 |
32 | _connection.VerifyConnection();
33 | var conn = _connection.GetConnection();
34 |
35 | policy.Execute(() => {
36 | conn.Publish(eventPath, body);
37 | conn.Flush();
38 | });
39 |
40 | return Task.CompletedTask;
41 | }
42 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.Nats/NatsEventSubscriber.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using Microsoft.Extensions.Options;
5 |
6 | namespace Enbiso.NLib.EventBus.Nats;
7 |
8 | public class NatsEventSubscriber: IEventSubscriber
9 | {
10 | private readonly INatsConnection _connection;
11 | private readonly IEventProcessor _eventProcessor;
12 | private readonly NatsOptions _options;
13 |
14 | public NatsEventSubscriber(INatsConnection connection, IOptions options, IEventProcessor eventProcessor)
15 | {
16 | _connection = connection;
17 | _eventProcessor = eventProcessor;
18 | _options = options.Value;
19 | }
20 |
21 | public void Dispose()
22 | {
23 | _connection?.Dispose();
24 | }
25 |
26 | public Task Subscribe(CancellationToken token = default)
27 | {
28 | _connection.Connected += conn =>
29 | {
30 | foreach (var exchange in _options.Exchanges ?? Array.Empty())
31 | {
32 | conn.SubscribeAsync($"{exchange}.>", _options.Client, async (sender, args) =>
33 | {
34 | var eventName = GetEventName(args.Message.Subject, exchange);
35 | await _eventProcessor.ProcessEvent(eventName, args.Message.Data);
36 | });
37 | }
38 | };
39 | _connection.VerifyConnection();
40 | return Task.CompletedTask;
41 | }
42 |
43 | private static string GetEventName(string subject, string exchange) =>
44 | subject.StartsWith(exchange)
45 | ? subject[(exchange.Length + 1)..]
46 | : subject;
47 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.Nats/NatsOptions.cs:
--------------------------------------------------------------------------------
1 | namespace Enbiso.NLib.EventBus.Nats
2 | {
3 | public class NatsOptions
4 | {
5 | public string[] Servers { get; set; }
6 | ///
7 | /// Rabbit server connection retries
8 | ///
9 | public int RetryCount { get; set; } = 5;
10 | ///
11 | /// Message publish retries
12 | ///
13 | public int PublishRetryCount { get; set; } = 5;
14 | ///
15 | /// Username
16 | ///
17 | public string Username { get; set; }
18 | ///
19 | /// Password
20 | ///
21 | public string Password { get; set; }
22 | ///
23 | /// Client (Queue) name
24 | ///
25 | public string Client { get; set; }
26 | ///
27 | /// Default brokers to publish messages
28 | ///
29 | public string PublishExchange { get; set; }
30 | ///
31 | /// Client brokers to get subscribed
32 | ///
33 | public string[] Exchanges { get; set; }
34 | ///
35 | /// Connection token
36 | ///
37 | public string Token { get; set; }
38 | ///
39 | /// Use NATS JetStream
40 | ///
41 | public bool EnableJetStream { get; set; } = false;
42 | ///
43 | /// Jet Stream poll batch size
44 | ///
45 | public int PollBatchSize { get; set; } = 1;
46 | ///
47 | /// Jet Stream poll wait ms
48 | ///
49 | public int PollWaitMills { get; set; } = 1000;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.Nats/NatsPolicyBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net.Sockets;
3 | using Microsoft.Extensions.Logging;
4 | using NATS.Client;
5 | using Polly;
6 | using Polly.Retry;
7 |
8 | namespace Enbiso.NLib.EventBus.Nats;
9 |
10 | public class NatsPolicyBuilder
11 | {
12 | public static RetryPolicy BuildPublishPolicy(int retryCount, ILogger logger)
13 | {
14 | var policy = Policy.Handle()
15 | .Or()
16 | .WaitAndRetry(retryCount,
17 | retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
18 | (ex, _) => { logger.LogWarning("{Error}",ex.ToString()); });
19 | return policy;
20 | }
21 |
22 | public static RetryPolicy BuildConnectPolicy(ILogger logger)
23 | {
24 | return Policy.Handle()
25 | .WaitAndRetryForever(
26 | _ => TimeSpan.FromSeconds(2),
27 | (ex, _) => logger.LogWarning("{Error}", ex.Message) );
28 | }
29 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.Nats/ServiceExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Enbiso.NLib.EventBus.Nats.JetStream;
3 | using Microsoft.Extensions.DependencyInjection;
4 | using NATS.Client;
5 |
6 | namespace Enbiso.NLib.EventBus.Nats
7 | {
8 | public static class ServiceExtensions
9 | {
10 | ///
11 | /// Add Event bus with default connection and manager
12 | ///
13 | ///
14 | ///
15 | public static void AddEventBusNats(this IServiceCollection services, Action option)
16 | {
17 | services.Configure(option);
18 |
19 | services.AddEventBus();
20 | services.AddSingleton();
21 | services.AddSingleton();
22 |
23 | var opts = new NatsOptions();
24 | option.Invoke(opts);
25 |
26 | if (opts.EnableJetStream)
27 | {
28 | services.AddSingleton();
29 | services.AddSingleton();
30 | services.AddSingleton();
31 | }
32 | else
33 | {
34 | services.AddSingleton();
35 | services.AddSingleton();
36 | }
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.RabbitMq/Enbiso.NLib.EventBus.RabbitMq.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netstandard2.1
4 | Enbiso.NLib.EventBus.RabbitMq
5 |
6 | 0.0.1-local
7 | $(PACKAGE_VERSION)
8 |
9 | Faraj Farook
10 | RabbitMq Implementation of EventBus
11 | false
12 | $(PACKAGE_COPYRIGHT)
13 | Enbiso Enbiso.NLib EventBus RabbitMq
14 | true
15 | en-AU
16 | enbiso
17 | Initial Release
18 | Enbiso - RabbitMq Implementation of EventBus in .NET Standard
19 | RabbitMq Impl EventBus
20 |
21 | logo.png
22 | $(PACKAGE_PROJECT)
23 | $(PACKAGE_REPO)
24 | default
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.RabbitMq/RabbitMqBusPublisher.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net.Sockets;
5 | using System.Text;
6 | using System.Text.Json;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 | using Microsoft.Extensions.Logging;
10 | using Microsoft.Extensions.Options;
11 | using Polly;
12 | using RabbitMQ.Client;
13 | using RabbitMQ.Client.Exceptions;
14 |
15 | namespace Enbiso.NLib.EventBus.RabbitMq
16 | {
17 | public class RabbitMqBusPublisher: IEventPublisher
18 | {
19 | private readonly IRabbitMqConnection _connection;
20 | private readonly ILogger _logger;
21 | private readonly RabbitMqOption _options;
22 |
23 | public RabbitMqBusPublisher(IRabbitMqConnection connection, IOptions options, ILogger logger)
24 | {
25 | _connection = connection;
26 | _logger = logger;
27 | _options = options.Value;
28 | }
29 |
30 | public Task Publish(TEvent @event, string exchange, string eventType, CancellationToken cancellationToken) where TEvent : IEvent
31 | {
32 | var policy = Policy.Handle()
33 | .Or()
34 | .WaitAndRetry(_options.PublishRetryCount,
35 | retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, _) =>
36 | {
37 | _logger.LogWarning(ex.ToString());
38 | });
39 |
40 | _connection.VerifyConnection();
41 |
42 | exchange ??= _options.PublishExchange ?? _options.Exchanges.FirstOrDefault();
43 | var channel = _connection.CreateModel();
44 | channel.ExchangeDeclare(exchange: exchange, type: "direct");
45 |
46 | var message = JsonSerializer.Serialize(@event);
47 | var body = Encoding.UTF8.GetBytes(message);
48 |
49 | eventType ??= @event.GetType().Name;
50 |
51 | policy.Execute(() =>
52 | {
53 | channel.BasicPublish(exchange, eventType, null, body);
54 | });
55 |
56 | return Task.CompletedTask;
57 | }
58 | }
59 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.RabbitMq/RabbitMqBusSubscriber.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using Microsoft.Extensions.Options;
6 | using RabbitMQ.Client;
7 | using RabbitMQ.Client.Events;
8 |
9 | namespace Enbiso.NLib.EventBus.RabbitMq
10 | {
11 | public class RabbitMqBusSubscriber: IEventSubscriber
12 | {
13 | private IModel _consumerChannel;
14 | private readonly IRabbitMqConnection _connection;
15 | private readonly IEventProcessor _eventProcessor;
16 | private readonly string _queueName;
17 | private readonly IEnumerable _exchanges;
18 |
19 | public RabbitMqBusSubscriber(IRabbitMqConnection connection, IEventProcessor eventProcessor,
20 | IOptions optionWrap, IEventTypeManager eventTypeManager)
21 | {
22 | var option = optionWrap.Value;
23 | _queueName = option.Client;
24 | _exchanges = option.Exchanges ?? Array.Empty();
25 |
26 | _connection = connection;
27 | _eventProcessor = eventProcessor;
28 |
29 | eventTypeManager.OnEventTypeAdded((_, args) =>
30 | {
31 | using var channel = _connection.CreateModel();
32 | foreach (var exchange in _exchanges)
33 | channel.QueueBind(queue: _queueName, exchange: exchange, routingKey: args.EventType.Name);
34 | });
35 | }
36 |
37 | private IModel CreateConsumerChannel()
38 | {
39 | _connection.VerifyConnection();
40 | var channel = _connection.CreateModel();
41 | foreach (var exchange in _exchanges)
42 | {
43 | channel.ExchangeDeclare(exchange: exchange, type: "direct");
44 | }
45 |
46 | channel.QueueDeclare(queue: _queueName, durable: true, exclusive: false, autoDelete: false, arguments: null);
47 | channel.CallbackException += (sender, ea) =>
48 | {
49 | _consumerChannel.Dispose();
50 | _consumerChannel = CreateConsumerChannel();
51 | };
52 | return channel;
53 | }
54 |
55 | public void Dispose()
56 | {
57 | _consumerChannel?.Dispose();
58 | }
59 |
60 | public Task Subscribe(CancellationToken token = default)
61 | {
62 | _consumerChannel = CreateConsumerChannel();
63 | var consumer = new EventingBasicConsumer(_consumerChannel);
64 | consumer.Received += async (model, ea) =>
65 | {
66 | var eventName = ea.RoutingKey;
67 | await _eventProcessor.ProcessEvent(eventName, ea.Body.ToArray());
68 | // ACK
69 | _consumerChannel.BasicAck(ea.DeliveryTag, multiple:false);
70 | };
71 | _consumerChannel.BasicConsume(queue: _queueName, autoAck: false, consumer: consumer);
72 | return Task.CompletedTask;
73 | }
74 | }
75 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.RabbitMq/RabbitMqConnection.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net.Sockets;
3 | using System.Threading.Tasks;
4 | using Microsoft.Extensions.Logging;
5 | using Microsoft.Extensions.Options;
6 | using Polly;
7 | using RabbitMQ.Client;
8 | using RabbitMQ.Client.Events;
9 | using RabbitMQ.Client.Exceptions;
10 |
11 | namespace Enbiso.NLib.EventBus.RabbitMq
12 | {
13 | public interface IRabbitMqConnection : IDisposable
14 | {
15 | ///
16 | /// Verify Connection
17 | ///
18 | void VerifyConnection();
19 |
20 | ///
21 | /// Create Model
22 | ///
23 | ///
24 | IModel CreateModel();
25 | }
26 |
27 | public class RabbitMqConnection : IRabbitMqConnection
28 | {
29 | private IConnection _connection;
30 | private bool _disposed;
31 | private readonly IConnectionFactory _connectionFactory;
32 | private readonly ILogger _logger;
33 | private readonly int _retryCount;
34 | private readonly object _syncRoot = new object();
35 |
36 | ///
37 | /// Create default Rabbit connection
38 | ///
39 | ///
40 | ///
41 | public RabbitMqConnection(
42 | ILogger logger,
43 | IOptions option)
44 | {
45 | var optVal = option.Value;
46 | _connectionFactory = new ConnectionFactory
47 | {
48 | HostName = optVal.Server ?? throw new ArgumentNullException(nameof(optVal.Server)),
49 | Port = optVal.Port
50 | };
51 | if (!string.IsNullOrEmpty(optVal.Username))
52 | _connectionFactory.UserName = optVal.Username;
53 | if (!string.IsNullOrEmpty(optVal.Password))
54 | _connectionFactory.Password = optVal.Password;
55 | if (!string.IsNullOrEmpty(optVal.VirtualHost))
56 | _connectionFactory.VirtualHost = optVal.VirtualHost;
57 | _logger = logger ?? throw new ArgumentNullException(nameof(logger));
58 | _retryCount = optVal.RetryCount;
59 | }
60 |
61 | private bool IsConnected
62 | => _connection != null && _connection.IsOpen && !_disposed;
63 |
64 | ///
65 | public void Dispose()
66 | {
67 | if (_disposed) return;
68 | _disposed = true;
69 | try
70 | {
71 | _connection.Dispose();
72 | }
73 | catch (Exception ex)
74 | {
75 | _logger.LogCritical(ex.ToString());
76 | }
77 | }
78 |
79 | private bool TryConnect()
80 | {
81 | _logger.LogInformation("RabbitMQ Client is trying to connect");
82 | lock (_syncRoot)
83 | {
84 | var policy = Policy.Handle()
85 | .Or()
86 | .WaitAndRetry(_retryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
87 | (ex, time) =>
88 | {
89 | _logger.LogWarning(ex.ToString());
90 | });
91 |
92 | policy.Execute(() =>
93 | {
94 | _connection = _connectionFactory.CreateConnection();
95 | });
96 |
97 | if (!IsConnected)
98 | {
99 | _logger.LogCritical("FATAL ERROR: RabbitMQ connections could not be created and opened");
100 | return false;
101 | }
102 |
103 | _connection.ConnectionShutdown += OnConnectionShutdown;
104 | _connection.CallbackException += OnCallbackException;
105 | _connection.ConnectionBlocked += OnConnectionBlocked;
106 |
107 | _logger.LogInformation(
108 | $"RabbitMQ persistent connection acquired a connection {_connection.Endpoint.HostName} and is subscribed to failure events");
109 | return true;
110 | }
111 | }
112 |
113 | public void VerifyConnection()
114 | {
115 | if(!IsConnected && !TryConnect())
116 | throw new Exception("Unable to connect to Rabbit MQ");
117 | }
118 |
119 | public IModel CreateModel()
120 | {
121 | VerifyConnection();
122 | return _connection.CreateModel();
123 | }
124 |
125 | #region private methods
126 |
127 | private void OnConnectionBlocked(object sender, ConnectionBlockedEventArgs e)
128 | {
129 | if (_disposed) return;
130 | _logger.LogWarning("A RabbitMQ connection is shutdown. Trying to re-connect...");
131 | TryConnect();
132 | }
133 |
134 | private void OnCallbackException(object sender, CallbackExceptionEventArgs e)
135 | {
136 | if (_disposed) return;
137 | _logger.LogWarning("A RabbitMQ connection throw exception. Trying to re-connect...");
138 | TryConnect();
139 | }
140 |
141 | private void OnConnectionShutdown(object sender, ShutdownEventArgs reason)
142 | {
143 | if (_disposed) return;
144 | _logger.LogWarning("A RabbitMQ connection is on shutdown. Trying to re-connect...");
145 | TryConnect();
146 | }
147 |
148 | #endregion
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.RabbitMq/RabbitMqOption.cs:
--------------------------------------------------------------------------------
1 | namespace Enbiso.NLib.EventBus.RabbitMq
2 | {
3 | public class RabbitMqOption
4 | {
5 | ///
6 | /// Server host
7 | ///
8 | public string Server { get; set; } = "localhost";
9 | ///
10 | /// Server Port
11 | ///
12 | public int Port { get; set; } = 5672;
13 | ///
14 | /// Username
15 | ///
16 | public string Username { get; set; }
17 | ///
18 | /// Password
19 | ///
20 | public string Password { get; set; }
21 | ///
22 | /// Virtual hosts
23 | ///
24 | public string VirtualHost { get; set; }
25 | ///
26 | /// Rabbit server connection retries
27 | ///
28 | public int RetryCount { get; set; } = 5;
29 | ///
30 | /// Message publish retries
31 | ///
32 | public int PublishRetryCount { get; set; } = 5;
33 | ///
34 | /// Client (Queue) name
35 | ///
36 | public string Client { get; set; }
37 | ///
38 | /// Default publish broker
39 | ///
40 | public string PublishExchange { get; set; }
41 | ///
42 | /// Client brokers name
43 | ///
44 | public string[] Exchanges { get; set; }
45 | }
46 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus.RabbitMq/ServiceExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.Extensions.Configuration;
3 | using Microsoft.Extensions.DependencyInjection;
4 |
5 | namespace Enbiso.NLib.EventBus.RabbitMq
6 | {
7 | public static class ServiceExtensions
8 | {
9 | ///
10 | /// Add Event bus wth custom connection and subscription manager
11 | ///
12 | ///
13 | ///
14 | public static void AddEventBusRabbitMq(this IServiceCollection services, Action option)
15 | {
16 | services.Configure(option);
17 |
18 | services.AddSingleton();
19 | services.AddSingleton();
20 | services.AddSingleton();
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus/Enbiso.NLib.EventBus.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | Enbiso.NLib.EventBus
6 |
7 | 0.0.1-local
8 | $(PACKAGE_VERSION)
9 |
10 | Faraj Farook
11 | Simple Abstract event bus library
12 | false
13 | $(PACKAGE_COPYRIGHT)
14 | Enbiso Enbiso.NLib EventBus
15 | true
16 | en-AU
17 | enbiso
18 | Initial Release
19 | Enbiso - Simple Abstract EventBus Library in .NET Standard
20 | Simple Abstract EventBus
21 |
22 | logo.png
23 | $(PACKAGE_PROJECT)
24 | $(PACKAGE_REPO)
25 | default
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus/Event.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Enbiso.NLib.EventBus
4 | {
5 | ///
6 | /// Integration event abstraction
7 | ///
8 | public abstract class Event : IEvent
9 | {
10 | protected Event()
11 | {
12 | EventId = Guid.NewGuid();
13 | EventCreationDate = DateTime.UtcNow;
14 | }
15 |
16 | public Guid EventId { get; }
17 | public DateTime EventCreationDate { get; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus/EventProcessor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Text.Json;
6 | using System.Threading.Tasks;
7 | using Microsoft.Extensions.Logging;
8 |
9 | namespace Enbiso.NLib.EventBus
10 | {
11 | public interface IEventProcessor
12 | {
13 | Task ProcessEvent(string eventName, byte[] data);
14 | void AddEventHandler(IEventHandler handler);
15 | }
16 |
17 | public class EventProcessor: IEventProcessor
18 | {
19 | private readonly List _eventHandlers = new();
20 | private readonly ILogger _logger;
21 | private readonly IEventTypeManager _eventTypeManager;
22 |
23 | public EventProcessor(IEnumerable eventHandlers, ILogger logger,
24 | IEventTypeManager eventTypeManager)
25 | {
26 | _logger = logger;
27 | _eventTypeManager = eventTypeManager;
28 | foreach (var eventHandler in eventHandlers)
29 | AddEventHandler(eventHandler);
30 | }
31 |
32 | public async Task ProcessEvent(string eventName, byte[] data)
33 | {
34 | var message = Encoding.UTF8.GetString(data);
35 |
36 | foreach (var eventHandler in _eventHandlers.Where(h => h.IsValidFor(eventName)))
37 | {
38 | var eventType = eventHandler.EventType;
39 | var @event = JsonSerializer.Deserialize(message, eventType);
40 |
41 | var eventId = @event is IEvent iEvent ? iEvent.EventId : Guid.Empty;
42 | try
43 | {
44 | _logger.LogTrace("Processing {EventType} {EventId}", eventType, eventId);
45 | await eventHandler.Handle(@event);
46 | }
47 | catch (Exception e)
48 | {
49 | _logger.LogError(e, "Error Processing {EventType} {EventId}", eventType, eventId);
50 | }
51 | }
52 | }
53 |
54 | public void AddEventHandler(IEventHandler handler)
55 | {
56 | _eventHandlers.Add(handler);
57 | _eventTypeManager.Add(handler.EventType);
58 | }
59 | }
60 |
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus/EventService.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 |
6 | namespace Enbiso.NLib.EventBus
7 | {
8 | public class EventService : IEventService
9 | {
10 | private readonly IEnumerable _publishers;
11 |
12 | public EventService(IEnumerable publishers)
13 | {
14 | _publishers = publishers;
15 | }
16 |
17 | public Task PublishToBus(T @event, string exchange, string eventType, CancellationToken token) where T : IEvent =>
18 | Task.WhenAll(_publishers.Select(p => p.Publish(@event, exchange, eventType, token)));
19 |
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus/EventSubscriptionService.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 |
6 | namespace Enbiso.NLib.EventBus
7 | {
8 | public class EventSubscriptionService : IEventSubscriptionService
9 | {
10 | private readonly IEnumerable _subscribers;
11 |
12 | public EventSubscriptionService(IEnumerable subscribers)
13 | {
14 | _subscribers = subscribers;
15 | }
16 |
17 | public Task SubscribeAll(CancellationToken token = default) =>
18 | Task.WhenAll(_subscribers.Select(s => s.Subscribe(token)));
19 | }
20 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus/EventTypeManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace Enbiso.NLib.EventBus;
5 |
6 | public interface IEventTypeManager
7 | {
8 | public void Add(Type eventType);
9 | public void OnEventTypeAdded(EventTypeAddedEventHandler handler);
10 | }
11 |
12 | public class EventTypeManager: IEventTypeManager
13 | {
14 | private readonly List _eventTypes = new();
15 | private event EventTypeAddedEventHandler EventTypeAdded;
16 |
17 | public void Add(Type eventType)
18 | {
19 | if (_eventTypes.Contains(eventType)) return;
20 | _eventTypes.Add(eventType);
21 | EventTypeAdded?.Invoke(this, new EventTypeAddedEventArgs(eventType));
22 | }
23 |
24 | public void OnEventTypeAdded(EventTypeAddedEventHandler handler)
25 | {
26 | ReplayEventsForHandler(handler);
27 | EventTypeAdded += handler;
28 | }
29 |
30 | private void ReplayEventsForHandler(EventTypeAddedEventHandler handler)
31 | {
32 | foreach (var eventType in _eventTypes)
33 | handler(this, new EventTypeAddedEventArgs(eventType));
34 | }
35 | }
36 |
37 |
38 | public class EventTypeAddedEventArgs: EventArgs
39 | {
40 | public EventTypeAddedEventArgs(Type eventType)
41 | {
42 | EventType = eventType;
43 | }
44 |
45 | public Type EventType { get; }
46 | }
47 |
48 | public delegate void EventTypeAddedEventHandler(object sender, EventTypeAddedEventArgs e);
--------------------------------------------------------------------------------
/Enbiso.NLib.EventBus/ServiceExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 |
3 | namespace Enbiso.NLib.EventBus
4 | {
5 | public static class ServiceExtensions
6 | {
7 | ///
8 | /// Add Event bus with default connection and manager
9 | ///
10 | ///
11 | public static void AddEventBus(this IServiceCollection services)
12 | {
13 | services.AddSingleton();
14 | services.AddSingleton();
15 | services.AddSingleton();
16 | services.AddTransient();
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventInfo/Enbiso.NLib.EventInfo.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net7.0
4 | Enbiso.NLib.EventInfo
5 |
6 | 0.0.1-local
7 | $(PACKAGE_VERSION)
8 |
9 | Faraj Farook
10 | EventInfo for integration events
11 | false
12 | $(PACKAGE_COPYRIGHT)
13 | Enbiso Enbiso.NLib EventInfo
14 | true
15 | en-AU
16 | enbiso
17 | Initial Release
18 | Enbiso - EventInfo for integration events in .NET
19 | EventInfo for integration events
20 |
21 | logo.png
22 | $(PACKAGE_PROJECT)
23 | $(PACKAGE_REPO)
24 | default
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Enbiso.NLib.EventInfo/EventInfoController.cs:
--------------------------------------------------------------------------------
1 | using Enbiso.NLib.EventInfo.Models;
2 | using Microsoft.AspNetCore.Mvc;
3 |
4 | namespace Enbiso.NLib.EventInfo;
5 |
6 | [Route("_events")]
7 | [ApiExplorerSettings(IgnoreApi = true)]
8 | public class EventInfoController: ControllerBase
9 | {
10 | private readonly IEventInfoService _eventInfoService;
11 |
12 | public EventInfoController(IEventInfoService eventInfoService)
13 | {
14 | _eventInfoService = eventInfoService;
15 | }
16 |
17 | [HttpGet]
18 | public EventInfoListResponse ListEvents() => _eventInfoService.List();
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/Enbiso.NLib.EventInfo/EventInfoService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using Enbiso.NLib.EventBus;
5 | using Enbiso.NLib.EventInfo.Models;
6 | using Microsoft.Extensions.Options;
7 |
8 | namespace Enbiso.NLib.EventInfo;
9 |
10 | public interface IEventInfoService
11 | {
12 | public EventInfoListResponse List();
13 | }
14 |
15 | public class EventInfoService: IEventInfoService
16 | {
17 | private EventInfoListResponse _response;
18 | private readonly EventInfoOption _option;
19 |
20 | public EventInfoService(IOptions option)
21 | {
22 | _option = option.Value;
23 | }
24 |
25 | public EventInfoListResponse List()
26 | {
27 | if (_response != null) return _response;
28 |
29 | var parentTypes = _option.SearchTypes ?? new List();
30 | parentTypes.Add(typeof(IEvent));
31 |
32 | var assemblies = AppDomain.CurrentDomain.GetAssemblies()
33 | .Where(p => !(p.FullName?.Contains("NLib") ?? false));
34 |
35 | var types = assemblies
36 | .SelectMany(s => s.GetTypes())
37 | .Where(t => t.IsClass)
38 | .Where(t => parentTypes.Any(pt => pt.IsAssignableFrom(t)));
39 |
40 | var records = types.Select(t => new EventRecord(t)).ToList();
41 | _response = new EventInfoListResponse
42 | {
43 | Records = records,
44 | Count = records.Count,
45 | };
46 | return _response;
47 | }
48 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventInfo/Models/EventInfoListResponse.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Enbiso.NLib.EventInfo.Models;
4 |
5 | public class EventInfoListResponse
6 | {
7 | public List Records { get; set; } = new();
8 | public int Count { get; set; }
9 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventInfo/Models/EventRecord.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | namespace Enbiso.NLib.EventInfo.Models;
6 |
7 | public class EventRecord
8 | {
9 | public string Name { get; }
10 | public List Props { get; }
11 |
12 | public EventRecord(Type type)
13 | {
14 | Name = type.Name;
15 | Props = type.GetProperties().Select(EventRecordMapper.Map).ToList();
16 | }
17 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventInfo/Models/EventRecordMapper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 |
6 | namespace Enbiso.NLib.EventInfo.Models;
7 |
8 | public static class EventRecordMapper
9 | {
10 | public static EventRecordProp Map(PropertyInfo property)
11 | {
12 | var prop = new EventRecordProp(property);
13 | if (!IsSimpleType(property.PropertyType))
14 | prop.Props = property.PropertyType.GetProperties()
15 | .Select(p => new EventRecordProp(p)).ToList();
16 | return prop;
17 | }
18 |
19 | private static bool ShouldExtract(Type type)
20 | {
21 | if (IsSimpleType(type)) return false;
22 | var excludeTypes = new List
23 | {
24 | typeof(List<>),
25 | typeof(IEnumerable<>),
26 | typeof(Dictionary<,>),
27 | typeof(IDictionary<,>)
28 | };
29 | return excludeTypes.All(p => p == type);
30 | }
31 |
32 | private static bool IsSimpleType(Type type)
33 | {
34 | return
35 | type.IsPrimitive ||
36 | type.IsValueType ||
37 | new[]
38 | {
39 | typeof(string),
40 | typeof(decimal),
41 | typeof(DateTime),
42 | typeof(DateTimeOffset),
43 | typeof(TimeSpan),
44 | typeof(Guid)
45 | }.Contains(type) ||
46 | type.IsEnum ||
47 | Convert.GetTypeCode(type) != TypeCode.Object ||
48 | (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>) &&
49 | IsSimpleType(type.GetGenericArguments()[0]));
50 | }
51 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventInfo/Models/EventRecordProp.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Reflection;
3 |
4 | namespace Enbiso.NLib.EventInfo.Models;
5 |
6 | public class EventRecordProp
7 | {
8 | public EventRecordProp(PropertyInfo property)
9 | {
10 | Name = property.Name;
11 | Type = property.PropertyType.Name;
12 | }
13 |
14 | public string Name { get; }
15 | public string Type { get; }
16 | public List Props { get; set; }
17 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventInfo/ServiceExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Microsoft.Extensions.DependencyInjection;
4 |
5 | namespace Enbiso.NLib.EventInfo;
6 |
7 | public static class ServiceExtensions
8 | {
9 | public static IServiceCollection AddEventInfo(this IServiceCollection collection, Action optBuilder = null)
10 | {
11 | collection.AddOptions();
12 | optBuilder ??= _ => {};
13 | collection.Configure(optBuilder);
14 |
15 | collection.AddSingleton();
16 | return collection;
17 | }
18 | }
19 |
20 | public class EventInfoOption
21 | {
22 | public List SearchTypes { get; set; } = new();
23 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventLogger.EntityFramework/Enbiso.NLib.EventLogger.EntityFramework.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net7.0
4 | Enbiso.NLib.EventLogger.EntityFramework
5 | 0.0.1-local
6 | $(PACKAGE_VERSION)
7 | Faraj Farook
8 | EventLog Persistence with Entity Framework
9 | false
10 | $(PACKAGE_COPYRIGHT)
11 | Enbiso Enbiso.NLib EventLog
12 | true
13 | en-AU
14 | enbiso
15 | Initial Release
16 | Enbiso - EventLog Persistence with EF in .NET Standard
17 | EventLog Persistence using EF
18 | logo.png
19 | $(PACKAGE_PROJECT)
20 | $(PACKAGE_REPO)
21 | default
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/Enbiso.NLib.EventLogger.EntityFramework/EntityEventLogRepo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Data.Common;
3 | using System.Threading.Tasks;
4 | using Microsoft.EntityFrameworkCore;
5 |
6 | namespace Enbiso.NLib.EventLogger.EntityFramework
7 | {
8 | ///
9 | ///
10 | /// Entity Framework event log repo imelemtations
11 | ///
12 | ///
13 | public class EntityEventLogRepo: IEventLogRepo where TDbContext: DbContext
14 | {
15 | private readonly DbContext _context;
16 |
17 | public EntityEventLogRepo(TDbContext context)
18 | {
19 | _context = context;
20 | }
21 |
22 | ///
23 | /// Find by ID
24 | ///
25 | ///
26 | ///
27 | public Task FindByIdAsync(Guid id)
28 | {
29 | return _context.Set().FirstOrDefaultAsync(e => e.EventId == id);
30 | }
31 |
32 | ///
33 | /// Add
34 | ///
35 | ///
36 | ///
37 | public EventLog Add(EventLog eventLog)
38 | {
39 | return _context.Set().Add(eventLog).Entity;
40 | }
41 |
42 | ///
43 | /// Update
44 | ///
45 | ///
46 | ///
47 | public EventLog Update(EventLog eventLog)
48 | {
49 | return _context.Set().Update(eventLog).Entity;
50 | }
51 |
52 | ///
53 | /// Use transaction
54 | ///
55 | ///
56 | public void UseTransaction(DbTransaction transaction)
57 | {
58 | _context.Database.UseTransaction(transaction);
59 | }
60 |
61 | ///
62 | /// Save async
63 | ///
64 | ///
65 | public Task SaveChangesAsync()
66 | {
67 | return _context.SaveChangesAsync();
68 | }
69 | }
70 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventLogger.EntityFramework/EventLogEntityConfig.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Microsoft.EntityFrameworkCore.Metadata.Builders;
3 |
4 | namespace Enbiso.NLib.EventLogger.EntityFramework
5 | {
6 | ///
7 | ///
8 | /// Event log entity configurations
9 | ///
10 | public class EventLogEntityConfig : IEntityTypeConfiguration
11 | {
12 | public void Configure(EntityTypeBuilder builder)
13 | {
14 | builder.Ignore(e => e.State);
15 |
16 | builder.HasKey(e => e.EventId);
17 |
18 | builder.Property(e => e.EventId)
19 | .IsRequired();
20 |
21 | builder.Property(e => e.Content)
22 | .IsRequired();
23 |
24 | builder.Property(e => e.CreationTime)
25 | .IsRequired();
26 |
27 | builder.Property("_state")
28 | .IsRequired().HasColumnName("State");
29 |
30 | builder.Property(e => e.TimesSent)
31 | .IsRequired();
32 |
33 | builder.Property(e => e.EventTypeName)
34 | .IsRequired();
35 | }
36 | }
37 |
38 | ///
39 | /// Model builder extensions
40 | ///
41 | public static class ModelBuilderExtensions
42 | {
43 | public static ModelBuilder ApplyEventLoggerConfiguration(this ModelBuilder builder)
44 | {
45 | return builder.ApplyConfiguration(new EventLogEntityConfig());
46 | }
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/Enbiso.NLib.EventLogger.EntityFramework/ServiceExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Microsoft.Extensions.DependencyInjection;
3 |
4 | namespace Enbiso.NLib.EventLogger.EntityFramework
5 | {
6 | public static class ServiceExtensions
7 | {
8 | public static void AddEventLogger(this IServiceCollection services) where TDbContext: DbContext
9 | {
10 | services.AddEventLogger();
11 | services.AddTransient>();
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventLogger.Mongo/Enbiso.NLib.EventLogger.Mongo.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | Enbiso.NLib.EventLogger.Mongo
6 | 0.0.1-local
7 | $(PACKAGE_VERSION)
8 | Faraj Farook
9 | EventLog Persistence with MongoDb
10 | false
11 | $(PACKAGE_COPYRIGHT)
12 | Enbiso Enbiso.NLib EventLog
13 | true
14 | en-AU
15 | enbiso
16 | Initial Release
17 | Enbiso - EventLog Persistence with Mongo DB in .NET Standard
18 | EventLog Persistence using Mongo
19 | logo.png
20 | $(PACKAGE_PROJECT)
21 | $(PACKAGE_REPO)
22 | default
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Enbiso.NLib.EventLogger.Mongo/MongoEventLogRepo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Data.Common;
3 | using System.Threading.Tasks;
4 | using MongoDB.Bson.Serialization.Attributes;
5 | using MongoDB.Driver;
6 |
7 | namespace Enbiso.NLib.EventLogger.Mongo
8 | {
9 | public class MongoEventLog
10 | {
11 | [BsonId]
12 | public string Id { get; set; }
13 | public EventLog Log { get; set; }
14 | }
15 |
16 | public class MongoEventLogRepo : IEventLogRepo
17 | {
18 | private readonly IMongoCollection _logs;
19 | private readonly IMongoClient _client;
20 | public MongoEventLogRepo(IMongoClient client, string dbName)
21 | {
22 | _client = client;
23 | _logs = client.GetDatabase(dbName).GetCollection("eventLogs");
24 | }
25 |
26 | public Task FindByIdAsync(Guid id)
27 | => _logs.Find(l => l.Id == id.ToString()).FirstOrDefaultAsync().ContinueWith(t => t.Result?.Log);
28 |
29 | public EventLog Add(EventLog eventLog)
30 | {
31 | _logs.InsertOne(new MongoEventLog
32 | {
33 | Id = eventLog.EventId.ToString(),
34 | Log = eventLog
35 | });
36 | return eventLog;
37 | }
38 |
39 | public EventLog Update(EventLog eventLog) => _logs.FindOneAndUpdate(l => l.Id == eventLog.EventId.ToString(),
40 | Builders.Update.Set(l => l.Log, eventLog)).Log;
41 |
42 | public void UseTransaction(DbTransaction transaction) {}
43 |
44 | public Task SaveChangesAsync() { return Task.CompletedTask; }
45 | }
46 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventLogger.Mongo/ServiceExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using MongoDB.Driver;
3 |
4 | namespace Enbiso.NLib.EventLogger.Mongo
5 | {
6 | public static class ServiceExtensions
7 | {
8 | public static void AddEventLogger(this IServiceCollection services, string dbname)
9 | {
10 | services.AddEventLogger();
11 | services.AddTransient(sp => new MongoEventLogRepo(sp.GetService(), dbname));
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventLogger/Enbiso.NLib.EventLogger.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netstandard2.1
4 | Enbiso.NLib.EventLogger
5 |
6 | 0.0.1-local
7 | $(PACKAGE_VERSION)
8 |
9 | Faraj Farook
10 | EventLogs for integration events
11 | false
12 | $(PACKAGE_COPYRIGHT)
13 | Enbiso Enbiso.NLib EventLog
14 | true
15 | en-AU
16 | enbiso
17 | Initial Release
18 | Enbiso - EventLogs for integration events in .NET Standard
19 | EventLogs for integration events
20 |
21 | logo.png
22 | $(PACKAGE_PROJECT)
23 | $(PACKAGE_REPO)
24 | default
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Enbiso.NLib.EventLogger/EventLog.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text.Json;
3 | using Enbiso.NLib.EventBus;
4 |
5 | namespace Enbiso.NLib.EventLogger
6 | {
7 | public class EventLog
8 | {
9 | private EventLog() { }
10 | public EventLog(IEvent @event, string eventType)
11 | {
12 | EventId = @event.EventId;
13 | CreationTime = @event.EventCreationDate;
14 | EventTypeName = eventType ?? @event.GetType().FullName;
15 | Content = JsonSerializer.Serialize(@event);
16 | State = EventState.NotPublished;
17 | TimesSent = 0;
18 | }
19 | public Guid EventId { get; private set; }
20 | public string EventTypeName { get; private set; }
21 | private string _state;
22 |
23 | public EventState State
24 | {
25 | get => Enum.TryParse(_state, out var val) ? val : default(EventState);
26 | set => _state = value.ToString();
27 | }
28 |
29 | public int TimesSent { get; set; }
30 | public DateTime CreationTime { get; private set; }
31 | public string Content { get; private set; }
32 | }
33 |
34 | ///
35 | /// Event states
36 | ///
37 | public enum EventState
38 | {
39 | NotPublished = 0,
40 | Published = 1,
41 | Failed = 2
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Enbiso.NLib.EventLogger/EventLoggerEventService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 | using Enbiso.NLib.EventBus;
7 |
8 | namespace Enbiso.NLib.EventLogger
9 | {
10 | public class EventLoggerEventService: IEventService
11 | {
12 | private readonly IEnumerable _publishers;
13 | private readonly IEnumerable _subscribers;
14 | private readonly IEventLoggerService _service;
15 |
16 | public EventLoggerEventService(IEventLoggerService service, IEnumerable subscribers,
17 | IEnumerable publishers)
18 | {
19 | _service = service;
20 | _subscribers = subscribers;
21 | _publishers = publishers;
22 | }
23 |
24 | public async Task PublishToBus(T @event, string exchange, string eventType, CancellationToken token) where T: IEvent
25 | {
26 | await _service.SaveEventAsync(@event, eventType);
27 | try
28 | {
29 | await Task.WhenAll(_publishers.Select(p => p.Publish(@event, exchange, eventType, token)));
30 | await _service.MarkEventAsPublishedAsync(@event);
31 | }
32 | catch (Exception)
33 | {
34 | await _service.MarkEventAsFailedAsync(@event);
35 | throw;
36 | }
37 | }
38 |
39 | public Task SubscribeAll(CancellationToken token = default) =>
40 | Task.WhenAll(_subscribers.Select(s => s.Subscribe(token)));
41 |
42 | }
43 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventLogger/EventLoggerService.cs:
--------------------------------------------------------------------------------
1 | using System.Data.Common;
2 | using System.Threading.Tasks;
3 | using Enbiso.NLib.EventBus;
4 |
5 | namespace Enbiso.NLib.EventLogger
6 | {
7 | ///
8 | /// EventLogger service
9 | ///
10 | public interface IEventLoggerService
11 | {
12 | Task SaveEventAsync(IEvent @event, string eventType, DbTransaction transaction = null);
13 | Task MarkEventAsPublishedAsync(IEvent @event);
14 | Task MarkEventAsFailedAsync(IEvent @event);
15 | }
16 |
17 | ///
18 | ///
19 | /// Event logger implementation
20 | ///
21 | public class EventLoggerService : IEventLoggerService
22 | {
23 | private readonly IEventLogRepo _repo;
24 |
25 | public EventLoggerService(IEventLogRepo repo)
26 | {
27 | _repo = repo;
28 | }
29 |
30 | ///
31 | /// Save events
32 | ///
33 | ///
34 | ///
35 | ///
36 | ///
37 | public Task SaveEventAsync(IEvent @event, string eventType, DbTransaction transaction)
38 | {
39 | if (transaction != null)
40 | _repo.UseTransaction(transaction);
41 |
42 | var eventLogEntry = new EventLog(@event, eventType);
43 |
44 | _repo.Add(eventLogEntry);
45 | return _repo.SaveChangesAsync();
46 | }
47 |
48 | ///
49 | /// Mark @event as published
50 | ///
51 | ///
52 | ///
53 | public async Task MarkEventAsPublishedAsync(IEvent @event)
54 | {
55 | var eventLogEntry = await _repo.FindByIdAsync(@event.EventId);
56 | eventLogEntry.TimesSent++;
57 | eventLogEntry.State = EventState.Published;
58 | _repo.Update(eventLogEntry);
59 | await _repo.SaveChangesAsync();
60 | }
61 |
62 | ///
63 | /// Mark as failed
64 | ///
65 | ///
66 | ///
67 | public async Task MarkEventAsFailedAsync(IEvent @event)
68 | {
69 | var eventLogEntry = await _repo.FindByIdAsync(@event.EventId);
70 | eventLogEntry.State = EventState.Failed;
71 | _repo.Update(eventLogEntry);
72 | await _repo.SaveChangesAsync();
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/Enbiso.NLib.EventLogger/IEventLogRepo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Data.Common;
3 | using System.Threading.Tasks;
4 |
5 | namespace Enbiso.NLib.EventLogger
6 | {
7 | ///
8 | /// Event log repository
9 | ///
10 | public interface IEventLogRepo
11 | {
12 | Task FindByIdAsync(Guid id);
13 | EventLog Add(EventLog eventLog);
14 | EventLog Update(EventLog eventLog);
15 | void UseTransaction(DbTransaction transaction);
16 | Task SaveChangesAsync();
17 | }
18 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.EventLogger/ServiceExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using Enbiso.NLib.EventBus;
3 | using Microsoft.Extensions.DependencyInjection;
4 |
5 | namespace Enbiso.NLib.EventLogger
6 | {
7 | public static class ServiceExtensions
8 | {
9 | public static void AddEventLogger(this IServiceCollection services)
10 | {
11 | services.AddTransient();
12 |
13 | var eventService = services.FirstOrDefault(descriptor => descriptor.ServiceType == typeof(IEventService));
14 | if (eventService != null) services.Remove(eventService);
15 |
16 | services.AddTransient();
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.GlobalExceptions/Enbiso.NLib.GlobalExceptions.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net7.0
4 | Enbiso.NLib.GlobalExceptions
5 |
6 | 0.0.1-local
7 | $(PACKAGE_VERSION)
8 |
9 | Faraj Farook
10 | Simple Global Exception handler
11 | false
12 | $(PACKAGE_COPYRIGHT)
13 | Enbiso Enbiso.NLib GlobalExceptions
14 | true
15 | en-AU
16 | enbiso
17 | Initial Release
18 | Enbiso - Simple Global Exception handler in .NET Standard
19 | Simple Global Exception handler
20 |
21 | logo.png
22 | $(PACKAGE_PROJECT)
23 | $(PACKAGE_REPO)
24 | default
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/Enbiso.NLib.GlobalExceptions/GlobalExceptionFilter.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using Microsoft.AspNetCore.Mvc;
5 | using Microsoft.AspNetCore.Mvc.Filters;
6 | using Microsoft.Extensions.Logging;
7 |
8 | namespace Enbiso.NLib.GlobalExceptions
9 | {
10 | public class GlobalExceptionFilter : IAsyncExceptionFilter
11 | {
12 | private readonly ILogger _logger;
13 | private readonly IEnumerable _handlers;
14 |
15 | public GlobalExceptionFilter(ILogger logger, IEnumerable handlers)
16 | {
17 | _logger = logger;
18 | _handlers = handlers;
19 | }
20 |
21 | public async Task OnExceptionAsync(ExceptionContext context)
22 | {
23 | _logger.LogError(new EventId(context.Exception.HResult),
24 | context.Exception,
25 | context.Exception.Message);
26 |
27 | var handler = _handlers.FirstOrDefault(h => h.ValidTypes.Contains(context.Exception.GetType()));
28 | if (handler != null)
29 | {
30 | var result = await handler.HandleException(context.Exception);
31 | context.Result = new ObjectResult(new
32 | {
33 | result.Content,
34 | ErrorType = context.Exception.GetType().Name
35 | });
36 | context.HttpContext.Response.StatusCode = result.StatusCode;
37 | context.ExceptionHandled = true;
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Enbiso.NLib.GlobalExceptions/GlobalExceptionHandler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 |
5 | namespace Enbiso.NLib.GlobalExceptions
6 | {
7 | ///
8 | /// Global exception handler interface
9 | ///
10 | public interface IGlobalExceptionHandler
11 | {
12 | IEnumerable ValidTypes { get; }
13 |
14 | Task HandleException(Exception exception);
15 | }
16 |
17 | ///
18 | /// Abstract Global exception handler
19 | ///
20 | ///
21 | public abstract class GlobalExceptionHandler : IGlobalExceptionHandler
22 | where TException : Exception
23 | {
24 | public IEnumerable ValidTypes => new [] { typeof(TException) };
25 | protected abstract Task Handle(TException ex);
26 |
27 | public Task HandleException(Exception exception)
28 | {
29 | if (exception is TException ex)
30 | {
31 | return Handle(ex);
32 | }
33 | return null;
34 | }
35 |
36 | }
37 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.GlobalExceptions/GlobalExceptionHandlerExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace Enbiso.NLib.GlobalExceptions
4 | {
5 | public static class GlobalExceptionHandlerExtensions
6 | {
7 | public static Task BadRequest(this IGlobalExceptionHandler handler, object result)
8 | {
9 | return Task.FromResult(new GlobalExceptionResponse(result, 400));
10 | }
11 |
12 | public static Task UnProcessableEntity(this IGlobalExceptionHandler handler, object result)
13 | {
14 | return Task.FromResult(new GlobalExceptionResponse(result, 422));
15 | }
16 |
17 | public static Task NotFound(this IGlobalExceptionHandler handler, object result)
18 | {
19 | return Task.FromResult(new GlobalExceptionResponse(result, 404));
20 | }
21 |
22 | public static Task Ok(this IGlobalExceptionHandler handler, object result)
23 | {
24 | return Task.FromResult(new GlobalExceptionResponse(result, 200));
25 | }
26 |
27 | public static Task InternalServerError(this IGlobalExceptionHandler handler, object result)
28 | {
29 | return Task.FromResult(new GlobalExceptionResponse(result, 500));
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Enbiso.NLib.GlobalExceptions/GlobalExceptionResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Enbiso.NLib.GlobalExceptions
4 | {
5 | ///
6 | /// Exception handler response with type
7 | ///
8 | public class GlobalExceptionResponse
9 | {
10 | public object Content { get; set; }
11 | public int StatusCode { get; set; }
12 | public GlobalExceptionResponse(object content, int statusCode)
13 | {
14 | Content = content;
15 | StatusCode = statusCode;
16 | }
17 |
18 | }
19 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.HttpContextService/Enbiso.NLib.HttpContextService.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net7.0
4 | Enbiso.NLib.HttpContextService
5 |
6 | 0.0.1-local
7 | $(PACKAGE_VERSION)
8 |
9 | Faraj Farook
10 | Http Context Fetcher
11 | false
12 | $(PACKAGE_COPYRIGHT)
13 | Enbiso Enbiso.NLib HttpContextService
14 | true
15 | en-AU
16 | enbiso
17 | Initial Release
18 | Enbiso - Http Context Fetcher in .NET Standard
19 | Simple Http Context Service
20 |
21 | logo.png
22 | $(PACKAGE_PROJECT)
23 | $(PACKAGE_REPO)
24 | default
25 | Enbiso.NLib.HttpContextService
26 | Library
27 | true
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/Enbiso.NLib.HttpContextService/HttpContextFetcher.cs:
--------------------------------------------------------------------------------
1 | using System.Text.Json;
2 | using System.Threading.Tasks;
3 | using Microsoft.AspNetCore.Http;
4 | using Microsoft.AspNetCore.Routing;
5 |
6 | namespace Enbiso.NLib.HttpContextService;
7 |
8 | public enum HttpContextSource
9 | {
10 | Query,
11 | Route,
12 | JsonBody
13 | }
14 |
15 | public record HttpContextFetchRequest(HttpContextSource Source, string Name)
16 | {
17 | public static HttpContextFetchRequest FromQuery(string name) => new(HttpContextSource.Query, name);
18 | public static HttpContextFetchRequest FromRoute(string name) => new(HttpContextSource.Route, name);
19 | public static HttpContextFetchRequest FromJsonBody(string name) => new(HttpContextSource.JsonBody, name);
20 | }
21 |
22 | public interface IHttpContextFetcher
23 | {
24 | Task FromRoute(string name);
25 | Task FromJsonBody(string name);
26 | Task FromQuery(string name);
27 | }
28 |
29 | public class HttpContextFetcher : IHttpContextFetcher
30 | {
31 | private readonly IHttpContextAccessor _contextAccessor;
32 |
33 | public HttpContextFetcher(IHttpContextAccessor contextAccessor)
34 | {
35 | _contextAccessor = contextAccessor;
36 | }
37 |
38 | public Task FromRoute(string name)
39 | {
40 | var httpContext = _contextAccessor.HttpContext;
41 | return Task.FromResult(httpContext?.GetRouteValue(name) as string);
42 | }
43 |
44 | public async Task FromJsonBody(string name)
45 | {
46 | var httpContext = _contextAccessor.HttpContext;
47 | if (httpContext == null) return null;
48 | httpContext.Request.EnableBuffering();
49 | var jsonDocument = await JsonDocument.ParseAsync(httpContext.Request.Body);
50 | httpContext.Request.Body.Position = 0;
51 | return jsonDocument.RootElement.TryGetProperty(name, out var jsonProp) ? jsonProp.GetString() : null;
52 | }
53 |
54 | public Task FromQuery(string name)
55 | {
56 | var httpContext = _contextAccessor.HttpContext;
57 | if (httpContext == null) return null;
58 | var value = httpContext.Request.Query.TryGetValue(name, out var queryValue)
59 | ? queryValue.ToString()
60 | : null;
61 | return Task.FromResult(value);
62 | }
63 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.HttpContextService/HttpContextService.cs:
--------------------------------------------------------------------------------
1 | using System.Security.Claims;
2 | using System.Threading.Tasks;
3 | using Microsoft.AspNetCore.Http;
4 |
5 | namespace Enbiso.NLib.HttpContextService;
6 |
7 | public interface IHttpContextService
8 | {
9 | Task Fetch(HttpContextFetchRequest request);
10 | string ClaimValue(string name);
11 | string UserId();
12 | bool UserInRole(string role);
13 | }
14 |
15 | public class HttpContextService: IHttpContextService
16 | {
17 | private readonly IHttpContextAccessor _contextAccessor;
18 | private readonly IHttpContextFetcher _fetcher;
19 |
20 | public HttpContextService(IHttpContextAccessor contextAccessor, IHttpContextFetcher fetcher)
21 | {
22 | _contextAccessor = contextAccessor;
23 | _fetcher = fetcher;
24 | }
25 |
26 | public Task Fetch(HttpContextFetchRequest request)
27 | {
28 | var (httpContextDataSource, name) = request;
29 | return httpContextDataSource switch
30 | {
31 | HttpContextSource.Query => _fetcher.FromQuery(name),
32 | HttpContextSource.Route => _fetcher.FromRoute(name),
33 | HttpContextSource.JsonBody => _fetcher.FromJsonBody(name),
34 | _ => null
35 | };
36 | }
37 |
38 | public string ClaimValue(string name)
39 | {
40 | var user = _contextAccessor.HttpContext?.User;
41 | return user.FindFirstValue(name);
42 | }
43 |
44 | public string UserId()
45 | {
46 | return ClaimValue("sub") ?? ClaimValue(ClaimTypes.NameIdentifier);
47 | }
48 |
49 | public bool UserInRole(string role)
50 | {
51 | return _contextAccessor.HttpContext?.User.IsInRole(role) ?? false;
52 | }
53 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.HttpContextService/ServiceExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 |
3 | namespace Enbiso.NLib.HttpContextService;
4 |
5 | public static class ServiceExtensions
6 | {
7 | public static void AddHttpContextService(this IServiceCollection services)
8 | {
9 | services.AddHttpContextAccessor();
10 | services.AddSingleton();
11 | services.AddSingleton();
12 | }
13 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.Idempotency.EntityFramework/Enbiso.NLib.Idempotency.EntityFramework.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net7.0
4 | Enbiso.NLib.Idempotency.EntityFramework
5 |
6 | 0.0.1-local
7 | $(PACKAGE_VERSION)
8 |
9 | Faraj Farook
10 | Simple Idempotency with Request Persistence with EF
11 | false
12 | $(PACKAGE_COPYRIGHT)
13 | Enbiso Enbiso.NLib Idempotency RequestLog
14 | true
15 | en-AU
16 | enbiso
17 | Initial Release
18 | Enbiso - Simple Idempotency with Request Persistence with EF in .NET Standard
19 | Simple Idempotency with Request Persistence
20 |
21 | logo.png
22 | $(PACKAGE_PROJECT)
23 | $(PACKAGE_REPO)
24 | default
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Enbiso.NLib.Idempotency.EntityFramework/RequestLogEntityConfig.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Microsoft.EntityFrameworkCore.Metadata.Builders;
3 |
4 | namespace Enbiso.NLib.Idempotency.EntityFramework
5 | {
6 | public class RequestLogEntityConfig : IEntityTypeConfiguration
7 | {
8 | public void Configure(EntityTypeBuilder requestConfiguration)
9 | {
10 | requestConfiguration.Property(cr => cr.Name).IsRequired();
11 | requestConfiguration.Property(cr => cr.Time).IsRequired();
12 | }
13 | }
14 |
15 | ///
16 | /// Model builder extensions
17 | ///
18 | public static class ModelBuilderExtensions
19 | {
20 | public static ModelBuilder ApplyIdempotencyConfiguration(this ModelBuilder builder)
21 | {
22 | return builder.ApplyConfiguration(new RequestLogEntityConfig());
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Enbiso.NLib.Idempotency.EntityFramework/RequestLogRepo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using Microsoft.EntityFrameworkCore;
4 |
5 | namespace Enbiso.NLib.Idempotency.EntityFramework
6 | {
7 | ///
8 | ///
9 | /// Repo implementation in EF
10 | ///
11 | ///
12 | public class RequestLogRepo: IRequestLogRepo where TDbContext: DbContext
13 | {
14 | private readonly DbContext _context;
15 |
16 | public RequestLogRepo(TDbContext context)
17 | {
18 | _context = context;
19 | }
20 |
21 | public async Task FindAsync(Guid id)
22 | {
23 | return await _context.Set().FirstOrDefaultAsync(rl => rl.Id == id);
24 | }
25 |
26 | public RequestLog Add(RequestLog requestLog)
27 | {
28 | return _context.Set().Add(requestLog).Entity;
29 | }
30 |
31 | public Task SaveChangesAsync()
32 | {
33 | return _context.SaveChangesAsync();
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Enbiso.NLib.Idempotency.EntityFramework/ServiceExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Microsoft.Extensions.DependencyInjection;
3 |
4 | namespace Enbiso.NLib.Idempotency.EntityFramework
5 | {
6 | public static class ServiceExtensions
7 | {
8 | public static void AddIdempotency(this IServiceCollection services) where TDbContext : DbContext
9 | {
10 | services.AddIdempotency();
11 | services.AddTransient>();
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.Idempotency/Enbiso.NLib.Idempotency.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netstandard2.1
4 | Enbiso.NLib.Idempotency
5 |
6 | 0.0.1-local
7 | $(PACKAGE_VERSION)
8 |
9 | Faraj Farook
10 | Simple Idempotency with Client Request Persistence
11 | false
12 | $(PACKAGE_COPYRIGHT)
13 | Enbiso Enbiso.NLib Idempotency ClientRequest
14 | true
15 | en-AU
16 | enbiso
17 | Initial Release
18 | Enbiso - Simple Idempotency with Client Request Persistence in .NET Standard
19 | Simple Idempotency with Client Request Persistence
20 |
21 | logo.png
22 | $(PACKAGE_PROJECT)
23 | $(PACKAGE_REPO)
24 | default
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/Enbiso.NLib.Idempotency/IRequestLogRepo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 |
4 | namespace Enbiso.NLib.Idempotency
5 | {
6 | ///
7 | /// Request log repository
8 | ///
9 | public interface IRequestLogRepo
10 | {
11 | ///
12 | /// Find by ID
13 | ///
14 | ///
15 | ///
16 | Task FindAsync(Guid id);
17 |
18 | ///
19 | /// Add New
20 | ///
21 | ///
22 | ///
23 | RequestLog Add(RequestLog requestLog);
24 |
25 | ///
26 | /// Save changes
27 | ///
28 | ///
29 | Task SaveChangesAsync();
30 | }
31 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.Idempotency/IRequestManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 |
4 | namespace Enbiso.NLib.Idempotency
5 | {
6 | ///
7 | /// Request Manager Interface
8 | ///
9 | public interface IRequestManager
10 | {
11 | ///
12 | /// Find Async
13 | ///
14 | ///
15 | ///
16 | Task FindAsync(Guid id);
17 |
18 | ///
19 | /// Create request for command
20 | ///
21 | ///
22 | ///
23 | ///
24 | ///
25 | Task CreateRequestForAsync(Guid id, string response);
26 |
27 | ///
28 | /// Create Request Log by name
29 | ///
30 | ///
31 | ///
32 | ///
33 | ///
34 | Task CreateRequestAsync(Guid id, string name, string response);
35 | }
36 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.Idempotency/RequestLog.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Enbiso.NLib.Idempotency
4 | {
5 | ///
6 | /// Request Log
7 | ///
8 | public class RequestLog
9 | {
10 | public Guid Id { get; set; }
11 | public string Name { get; set; }
12 | public DateTime Time { get; set; }
13 | public string Response { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Enbiso.NLib.Idempotency/RequestManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 |
4 | namespace Enbiso.NLib.Idempotency
5 | {
6 | ///
7 | ///
8 | /// Request manager implementation
9 | ///
10 | public class RequestManager : IRequestManager
11 | {
12 | private readonly IRequestLogRepo _repo;
13 |
14 | public RequestManager(IRequestLogRepo repo)
15 | {
16 | _repo = repo;
17 | }
18 |
19 | public Task FindAsync(Guid id)
20 | {
21 | return _repo.FindAsync(id);
22 | }
23 |
24 | public Task CreateRequestForAsync(Guid id, string response)
25 | {
26 | return CreateRequestAsync(id, typeof(T).Name, response);
27 | }
28 |
29 | public async Task CreateRequestAsync(Guid id, string name, string response)
30 | {
31 | var request = new RequestLog
32 | {
33 | Id = id,
34 | Name = name,
35 | Time = DateTime.UtcNow,
36 | Response = response
37 | };
38 | _repo.Add(request);
39 | await _repo.SaveChangesAsync();
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.Idempotency/ServiceExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 |
3 | namespace Enbiso.NLib.Idempotency
4 | {
5 | public static class ServiceExtensions
6 | {
7 | public static void AddIdempotency(this IServiceCollection services)
8 | {
9 | services.AddTransient();
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.IdentityServer.Mongo/Enbiso.NLib.IdentityServer.Mongo.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | enable
6 | Enbiso.NLib.IdentityServer.Mongo
7 |
8 | 0.0.1-local
9 | $(PACKAGE_VERSION)
10 |
11 | Faraj Farook
12 | IdentityServer4 MongoDB data provider
13 | false
14 | $(PACKAGE_COPYRIGHT)
15 | Enbiso Enbiso.NLib IdentityServer IdentityServer4
16 | true
17 | en-AU
18 | enbiso
19 | Initial Release
20 | Enbiso - IdentityServer4 MongoDB data provider
21 | IdentityServer4 MongoDB data provider
22 |
23 | logo.png
24 | $(PACKAGE_PROJECT)
25 | $(PACKAGE_REPO)
26 | default
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/Enbiso.NLib.IdentityServer.Mongo/Events/IdentityServerMongoEvents.cs:
--------------------------------------------------------------------------------
1 | namespace Enbiso.NLib.IdentityServer.Mongo.Events;
2 |
3 | public interface IIdentityServerMongoEvent
4 | {
5 | }
6 |
7 | public interface IIdentityServerMongoEventHandler where TEvent: IIdentityServerMongoEvent
8 | {
9 | Task Handle(TEvent @event, CancellationToken cancellationToken);
10 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.IdentityServer.Mongo/Events/IdentityServerMongoUserEvents.cs:
--------------------------------------------------------------------------------
1 | namespace Enbiso.NLib.IdentityServer.Mongo.Events;
2 |
3 | public class IdentityServerMongoUserCreateEvent: IIdentityServerMongoEvent
4 | {
5 | public IdentityServerMongoUserCreateEvent(TUser user)
6 | {
7 | User = user;
8 | }
9 |
10 | public TUser User { get; }
11 | }
12 |
13 | public class IdentityServerMongoUserDeleteEvent: IIdentityServerMongoEvent
14 | {
15 | public IdentityServerMongoUserDeleteEvent(TUser user)
16 | {
17 | User = user;
18 | }
19 |
20 | public TUser User { get; }
21 | }
22 |
23 | public class IdentityServerMongoUserUpdateEvent: IIdentityServerMongoEvent
24 | {
25 | public IdentityServerMongoUserUpdateEvent(TUser user)
26 | {
27 | User = user;
28 | }
29 |
30 | public TUser User { get; }
31 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.IdentityServer.Mongo/Models/ApiResourceData.cs:
--------------------------------------------------------------------------------
1 | using Duende.IdentityServer.Models;
2 | using MongoDB.Bson.Serialization.Attributes;
3 |
4 | namespace Enbiso.NLib.IdentityServer.Mongo.Models
5 | {
6 | public class ApiResourceData
7 | {
8 | [BsonId]
9 | public string Id { get; set; }
10 |
11 | public ApiResource Resource { get; set; }
12 | }
13 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.IdentityServer.Mongo/Models/ClientData.cs:
--------------------------------------------------------------------------------
1 | using Duende.IdentityServer.Models;
2 | using MongoDB.Bson.Serialization.Attributes;
3 |
4 | namespace Enbiso.NLib.IdentityServer.Mongo.Models
5 | {
6 | public class ClientData
7 | {
8 | [BsonId]
9 | public string Id { get; set; }
10 | public Client Client { get; set; }
11 | }
12 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.IdentityServer.Mongo/Models/IMongoIdentityRole.cs:
--------------------------------------------------------------------------------
1 | namespace Enbiso.NLib.IdentityServer.Mongo.Models;
2 |
3 | public interface IMongoIdentityRole
4 | {
5 | public IList Claims { get; set; }
6 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.IdentityServer.Mongo/Models/IMongoIdentityUser.cs:
--------------------------------------------------------------------------------
1 | namespace Enbiso.NLib.IdentityServer.Mongo.Models;
2 |
3 | public interface IMongoIdentityUser
4 | {
5 | IList Roles { get; set; }
6 | IList Logins { get; set; }
7 | IList Claims { get; set; }
8 | string AuthenticatorKey { get; set; }
9 | IDictionary Tokens { get; set; }
10 | IList RecoveryCodes { get; set; }
11 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.IdentityServer.Mongo/Models/IdentityResourceData.cs:
--------------------------------------------------------------------------------
1 | using Duende.IdentityServer.Models;
2 | using MongoDB.Bson.Serialization.Attributes;
3 |
4 | namespace Enbiso.NLib.IdentityServer.Mongo.Models
5 | {
6 | public class IdentityResourceData
7 | {
8 | [BsonId]
9 | public string Id { get; set; }
10 |
11 | public IdentityResource Resource { get; set; }
12 | }
13 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.IdentityServer.Mongo/Models/MongoClaim.cs:
--------------------------------------------------------------------------------
1 | using System.Security.Claims;
2 | using MongoDB.Bson.Serialization.Attributes;
3 |
4 | namespace Enbiso.NLib.IdentityServer.Mongo.Models;
5 |
6 | [BsonIgnoreExtraElements]
7 | public class MongoClaim
8 | {
9 | public MongoClaim()
10 | {
11 |
12 | }
13 | public MongoClaim(Claim claim)
14 | {
15 | Type = claim.Type;
16 | Value = claim.Value;
17 | ValueType = claim.ValueType;
18 | Issuer = claim.Issuer;
19 | OriginalIssuer = claim.OriginalIssuer;
20 | }
21 |
22 | public Claim ToClaim() => new(Type, Value, ValueType, Issuer, OriginalIssuer);
23 | public string Type { get; set; }
24 | public string OriginalIssuer { get; set; }
25 | public string Issuer { get; set; }
26 | public string ValueType { get; set; }
27 | public string Value { get; set; }
28 |
29 | public override bool Equals(object obj)
30 | {
31 | return Equals(obj as MongoClaim);
32 | }
33 |
34 | public override int GetHashCode()
35 | {
36 | return HashCode.Combine(Type, OriginalIssuer, Issuer, ValueType, Value);
37 | }
38 |
39 | private bool Equals ( MongoClaim obj )
40 | {
41 | return obj != null && obj.Type == Type && obj.Value == Value;
42 | }
43 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.IdentityServer.Mongo/Models/MongoUserLoginInfo.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Identity;
2 | using MongoDB.Bson.Serialization.Attributes;
3 |
4 | namespace Enbiso.NLib.IdentityServer.Mongo.Models;
5 |
6 | [BsonIgnoreExtraElements]
7 | public class MongoUserLoginInfo : UserLoginInfo
8 | {
9 | public MongoUserLoginInfo(string loginProvider, string providerKey, string displayName) : base(loginProvider,
10 | providerKey, displayName)
11 | {
12 | }
13 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.IdentityServer.Mongo/Models/PersistedGrantData.cs:
--------------------------------------------------------------------------------
1 | using Duende.IdentityServer.Models;
2 | using MongoDB.Bson.Serialization.Attributes;
3 |
4 | namespace Enbiso.NLib.IdentityServer.Mongo.Models
5 | {
6 | public class PersistedGrantData
7 | {
8 | [BsonId]
9 | public string Id { get; set; }
10 |
11 | public PersistedGrant PersistedGrant { get; set; }
12 | }
13 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.IdentityServer.Mongo/Models/RecoveryCode.cs:
--------------------------------------------------------------------------------
1 | namespace Enbiso.NLib.IdentityServer.Mongo.Models;
2 |
3 | public class RecoveryCode
4 | {
5 | public string Code { get; set; }
6 | public bool Used { get; set; }
7 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.IdentityServer.Mongo/ServiceExtensions.cs:
--------------------------------------------------------------------------------
1 | using Duende.IdentityServer.Stores;
2 | using Enbiso.NLib.IdentityServer.Mongo.Models;
3 | using Enbiso.NLib.IdentityServer.Mongo.Stores;
4 | using Microsoft.AspNetCore.Identity;
5 | using Microsoft.Extensions.DependencyInjection;
6 | using MongoDB.Driver;
7 |
8 | namespace Enbiso.NLib.IdentityServer.Mongo
9 | {
10 | public static class ServiceExtensions
11 | {
12 | public static IServiceCollection AddIdentityServerMongo(this IServiceCollection services,
13 | Action optSetup)
14 | where TRole : IdentityRole, IMongoIdentityRole
15 | where TUser : IdentityUser, IMongoIdentityUser
16 | {
17 | var options = new IdentityServerMongoOptions();
18 | optSetup.Invoke(options);
19 | var mongo = new MongoClient(options.ConnectionString);
20 | var db = mongo.GetDatabase(options.Database);
21 | services.AddSingleton(sp => db.GetCollection(options.ClientCollection));
22 | services.AddSingleton(sp => db.GetCollection(options.PersistedGrantCollection));
23 | services.AddSingleton(sp => db.GetCollection(options.ApiResourceCollection));
24 | services.AddSingleton(sp => db.GetCollection(options.IdentityResourceCollection));
25 | services.AddSingleton(sp => db.GetCollection(options.RoleCollection));
26 | services.AddSingleton(sp => db.GetCollection(options.UserCollection));
27 |
28 | services.AddTransient();
29 | services.AddTransient();
30 | services.AddTransient();
31 | services.AddTransient, MongoUserStore>();
32 | services.AddTransient, MongoRoleStore>();
33 |
34 | return services;
35 | }
36 | }
37 |
38 | public class IdentityServerMongoOptions
39 | {
40 | public string ConnectionString { get; set; } = "localhost";
41 | public string Database { get; set; } = "identity";
42 | public string ClientCollection { get; set; } = "clients";
43 | public string PersistedGrantCollection { get; set; } = "persisted-grants";
44 | public string ApiResourceCollection { get; set; } = "api-resources";
45 | public string IdentityResourceCollection { get; set; } = "identity-resources";
46 | public string RoleCollection { get; set; } = "roles";
47 | public string UserCollection { get; set; } = "users";
48 | }
49 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.IdentityServer.Mongo/Stores/MongoClientStore.cs:
--------------------------------------------------------------------------------
1 | using Duende.IdentityServer.Models;
2 | using Duende.IdentityServer.Stores;
3 | using Enbiso.NLib.IdentityServer.Mongo.Models;
4 | using MongoDB.Driver;
5 |
6 | namespace Enbiso.NLib.IdentityServer.Mongo.Stores
7 | {
8 | public class MongoClientStore: IClientStore
9 | {
10 | private readonly IMongoCollection _clients;
11 |
12 | public MongoClientStore(IMongoCollection clients)
13 | {
14 | _clients = clients;
15 | }
16 |
17 | public async Task FindClientByIdAsync(string clientId)
18 | {
19 | var wrapper = await _clients.Find(c => c.Id == clientId).FirstOrDefaultAsync();
20 | return wrapper?.Client;
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/Enbiso.NLib.IdentityServer.Mongo/Stores/MongoPersistedGrantStore.cs:
--------------------------------------------------------------------------------
1 | using Duende.IdentityServer.Models;
2 | using Duende.IdentityServer.Stores;
3 | using Enbiso.NLib.IdentityServer.Mongo.Models;
4 | using MongoDB.Driver;
5 |
6 | namespace Enbiso.NLib.IdentityServer.Mongo.Stores
7 | {
8 | public class MongoPersistedGrantStore: IPersistedGrantStore
9 | {
10 |
11 | private readonly IMongoCollection _persistedGrants;
12 |
13 | public MongoPersistedGrantStore(IMongoCollection persistedGrants)
14 | {
15 | _persistedGrants = persistedGrants;
16 | }
17 |
18 | public async Task StoreAsync(PersistedGrant grant)
19 | {
20 | if(await _persistedGrants.Find(g => g.Id == grant.Key).AnyAsync())
21 | await RemoveAsync(grant.Key);
22 |
23 | await _persistedGrants.InsertOneAsync(new PersistedGrantData
24 | {
25 | Id = grant.Key,
26 | PersistedGrant = grant
27 | });
28 | }
29 |
30 |
31 | public Task GetAsync(string key) => _persistedGrants.Find(p => p.Id == key)
32 | .Project(p => p.PersistedGrant).FirstOrDefaultAsync();
33 |
34 | public Task