├── .DS_Store
├── .github
├── images
│ ├── tyrion.jpg
│ └── tyrion.png
└── workflows
│ ├── build.yml
│ └── main.yml
├── .gitignore
├── Directory.Build.props
├── README.md
├── Tyrion.CQRS.sln
├── _config.yml
├── appveyor.yml
├── azure-pipelines.yml
└── src
├── .DS_Store
├── LICENSE
├── Tyrion.Tests
├── Category
│ ├── Category.cs
│ ├── CategoryCommand.cs
│ ├── CategoryCommandHandler.cs
│ └── CategoryCommandValidator.cs
├── Product
│ ├── InativeProductCommand.cs
│ ├── LastProductInStockEvent.cs
│ ├── Product.cs
│ ├── ProductCommandHandler.cs
│ ├── ProductDiscountEmailEvent.cs
│ ├── ProductGiftEvent.cs
│ ├── ProductNotificationHandler.cs
│ ├── RemoveProductCommand.cs
│ ├── SaveProductCommand.cs
│ └── UpdateProductCommand.cs
├── Tyrion.Tests.csproj
└── TyrionTests.cs
└── Tyrion
├── .DS_Store
├── Extensions
├── ServiceCollectionExtensions.cs
└── TypeExtensions.cs
├── Handlers
├── INotification.cs
├── INotificationHandler.cs
├── IRequest.cs
└── IRequestHandler.cs
├── ITyrion.cs
├── Results
├── IResult.cs
└── Result.cs
├── Tyrion.cs
├── Tyrion.csproj
└── Validators
└── Validator.cs
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucaslab-dev/Tyrion/f287193a1eee57bc63912f76877b9281f34bd6c9/.DS_Store
--------------------------------------------------------------------------------
/.github/images/tyrion.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucaslab-dev/Tyrion/f287193a1eee57bc63912f76877b9281f34bd6c9/.github/images/tyrion.jpg
--------------------------------------------------------------------------------
/.github/images/tyrion.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucaslab-dev/Tyrion/f287193a1eee57bc63912f76877b9281f34bd6c9/.github/images/tyrion.png
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 | on:
3 | push:
4 | branches:
5 | - master
6 | pull_request:
7 | types: [opened, synchronize, reopened]
8 | jobs:
9 | build:
10 | name: Build
11 | runs-on: windows-latest
12 | steps:
13 | - name: Set up JDK 11
14 | uses: actions/setup-java@v1
15 | with:
16 | java-version: 1.11
17 | - uses: actions/checkout@v2
18 | with:
19 | fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
20 | - name: Cache SonarCloud packages
21 | uses: actions/cache@v1
22 | with:
23 | path: ~\sonar\cache
24 | key: ${{ runner.os }}-sonar
25 | restore-keys: ${{ runner.os }}-sonar
26 | - name: Cache SonarCloud scanner
27 | id: cache-sonar-scanner
28 | uses: actions/cache@v1
29 | with:
30 | path: .\.sonar\scanner
31 | key: ${{ runner.os }}-sonar-scanner
32 | restore-keys: ${{ runner.os }}-sonar-scanner
33 | - name: Install SonarCloud scanner
34 | if: steps.cache-sonar-scanner.outputs.cache-hit != 'true'
35 | shell: powershell
36 | run: |
37 | New-Item -Path .\.sonar\scanner -ItemType Directory
38 | dotnet tool update dotnet-sonarscanner --tool-path .\.sonar\scanner
39 | - name: Build and analyze
40 | env:
41 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
42 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
43 | shell: powershell
44 | run: |
45 | .\.sonar\scanner\dotnet-sonarscanner begin /k:"lucasluizss_Tyrion.CQRS" /o:"lucasluizss" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io"
46 | dotnet build
47 | dotnet test --collect "Code Coverage"
48 | .\.sonar\scanner\dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}"
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Build and deploy package
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | jobs:
9 | build-and-deploy:
10 | runs-on: ubuntu-latest
11 |
12 | steps:
13 | - uses: actions/checkout@main
14 |
15 | - name: Set up .NET Core
16 | uses: actions/setup-dotnet@v1
17 | with:
18 | dotnet-version: '7.0.x'
19 |
20 | - name: Build with dotnet
21 | run: dotnet build --configuration Release
22 |
23 | - name: Test
24 | run: dotnet test
25 |
26 | - name: Create the Package
27 | run: dotnet pack --configuration Release
28 |
29 | - name: Publish
30 | env:
31 | NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
32 | run: |
33 | find . -name "*.nupkg" -exec dotnet nuget push {} -k $NUGET_API_KEY -s https://api.nuget.org/v3/index.json \;
34 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 | *.bat
13 |
14 | # User-specific files (MonoDevelop/Xamarin Studio)
15 | *.userprefs
16 |
17 | # Mono auto generated files
18 | mono_crash.*
19 |
20 | # Build results
21 | [Dd]ebug/
22 | [Dd]ebugPublic/
23 | [Rr]elease/
24 | [Rr]eleases/
25 | x64/
26 | x86/
27 | [Aa][Rr][Mm]/
28 | [Aa][Rr][Mm]64/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Ll]og/
33 | [Ll]ogs/
34 |
35 | # Visual Studio 2015/2017 cache/options directory
36 | .vs/
37 | .vscode/
38 | # Uncomment if you have tasks that create the project's static files in wwwroot
39 | #wwwroot/
40 |
41 | # Visual Studio 2017 auto generated files
42 | Generated\ Files/
43 |
44 | # MSTest test Results
45 | [Tt]est[Rr]esult*/
46 | [Bb]uild[Ll]og.*
47 |
48 | # NUnit
49 | *.VisualState.xml
50 | TestResult.xml
51 | nunit-*.xml
52 |
53 | # Build Results of an ATL Project
54 | [Dd]ebugPS/
55 | [Rr]eleasePS/
56 | dlldata.c
57 |
58 | # Benchmark Results
59 | BenchmarkDotNet.Artifacts/
60 |
61 | # .NET Core
62 | project.lock.json
63 | project.fragment.lock.json
64 | artifacts/
65 |
66 | # StyleCop
67 | StyleCopReport.xml
68 |
69 | # Files built by Visual Studio
70 | *_i.c
71 | *_p.c
72 | *_h.h
73 | *.ilk
74 | *.meta
75 | *.obj
76 | *.iobj
77 | *.pch
78 | *.pdb
79 | *.ipdb
80 | *.pgc
81 | *.pgd
82 | *.rsp
83 | *.sbr
84 | *.tlb
85 | *.tli
86 | *.tlh
87 | *.tmp
88 | *.tmp_proj
89 | *_wpftmp.csproj
90 | *.log
91 | *.vspscc
92 | *.vssscc
93 | .builds
94 | *.pidb
95 | *.svclog
96 | *.scc
97 |
98 | # Chutzpah Test files
99 | _Chutzpah*
100 |
101 | # Visual C++ cache files
102 | ipch/
103 | *.aps
104 | *.ncb
105 | *.opendb
106 | *.opensdf
107 | *.sdf
108 | *.cachefile
109 | *.VC.db
110 | *.VC.VC.opendb
111 |
112 | # Visual Studio profiler
113 | *.psess
114 | *.vsp
115 | *.vspx
116 | *.sap
117 |
118 | # Visual Studio Trace Files
119 | *.e2e
120 |
121 | # TFS 2012 Local Workspace
122 | $tf/
123 |
124 | # Guidance Automation Toolkit
125 | *.gpState
126 |
127 | # ReSharper is a .NET coding add-in
128 | _ReSharper*/
129 | *.[Rr]e[Ss]harper
130 | *.DotSettings.user
131 |
132 | # TeamCity is a build add-in
133 | _TeamCity*
134 |
135 | # DotCover is a Code Coverage Tool
136 | *.dotCover
137 |
138 | # AxoCover is a Code Coverage Tool
139 | .axoCover/*
140 | !.axoCover/settings.json
141 |
142 | # Visual Studio code coverage results
143 | *.coverage
144 | *.coveragexml
145 |
146 | # NCrunch
147 | _NCrunch_*
148 | .*crunch*.local.xml
149 | nCrunchTemp_*
150 |
151 | # MightyMoose
152 | *.mm.*
153 | AutoTest.Net/
154 |
155 | # Web workbench (sass)
156 | .sass-cache/
157 |
158 | # Installshield output folder
159 | [Ee]xpress/
160 |
161 | # DocProject is a documentation generator add-in
162 | DocProject/buildhelp/
163 | DocProject/Help/*.HxT
164 | DocProject/Help/*.HxC
165 | DocProject/Help/*.hhc
166 | DocProject/Help/*.hhk
167 | DocProject/Help/*.hhp
168 | DocProject/Help/Html2
169 | DocProject/Help/html
170 |
171 | # Click-Once directory
172 | publish/
173 |
174 | # Publish Web Output
175 | *.[Pp]ublish.xml
176 | *.azurePubxml
177 | # Note: Comment the next line if you want to checkin your web deploy settings,
178 | # but database connection strings (with potential passwords) will be unencrypted
179 | *.pubxml
180 | *.publishproj
181 |
182 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
183 | # checkin your Azure Web App publish settings, but sensitive information contained
184 | # in these scripts will be unencrypted
185 | PublishScripts/
186 |
187 | # NuGet Packages
188 | *.nupkg
189 | # NuGet Symbol Packages
190 | *.snupkg
191 | # The packages folder can be ignored because of Package Restore
192 | **/[Pp]ackages/*
193 | # except build/, which is used as an MSBuild target.
194 | !**/[Pp]ackages/build/
195 | # Uncomment if necessary however generally it will be regenerated when needed
196 | #!**/[Pp]ackages/repositories.config
197 | # NuGet v3's project.json files produces more ignorable files
198 | *.nuget.props
199 | *.nuget.targets
200 |
201 | # Microsoft Azure Build Output
202 | csx/
203 | *.build.csdef
204 |
205 | # Microsoft Azure Emulator
206 | ecf/
207 | rcf/
208 |
209 | # Windows Store app package directories and files
210 | AppPackages/
211 | BundleArtifacts/
212 | Package.StoreAssociation.xml
213 | _pkginfo.txt
214 | *.appx
215 | *.appxbundle
216 | *.appxupload
217 |
218 | # Visual Studio cache files
219 | # files ending in .cache can be ignored
220 | *.[Cc]ache
221 | # but keep track of directories ending in .cache
222 | !?*.[Cc]ache/
223 |
224 | # Others
225 | ClientBin/
226 | ~$*
227 | *~
228 | *.dbmdl
229 | *.dbproj.schemaview
230 | *.jfm
231 | *.pfx
232 | *.publishsettings
233 | orleans.codegen.cs
234 |
235 | # Including strong name files can present a security risk
236 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
237 | #*.snk
238 |
239 | # Since there are multiple workflows, uncomment next line to ignore bower_components
240 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
241 | #bower_components/
242 |
243 | # RIA/Silverlight projects
244 | Generated_Code/
245 |
246 | # Backup & report files from converting an old project file
247 | # to a newer Visual Studio version. Backup files are not needed,
248 | # because we have git ;-)
249 | _UpgradeReport_Files/
250 | Backup*/
251 | UpgradeLog*.XML
252 | UpgradeLog*.htm
253 | ServiceFabricBackup/
254 | *.rptproj.bak
255 |
256 | # SQL Server files
257 | *.mdf
258 | *.ldf
259 | *.ndf
260 |
261 | # Business Intelligence projects
262 | *.rdl.data
263 | *.bim.layout
264 | *.bim_*.settings
265 | *.rptproj.rsuser
266 | *- [Bb]ackup.rdl
267 | *- [Bb]ackup ([0-9]).rdl
268 | *- [Bb]ackup ([0-9][0-9]).rdl
269 |
270 | # Microsoft Fakes
271 | FakesAssemblies/
272 |
273 | # GhostDoc plugin setting file
274 | *.GhostDoc.xml
275 |
276 | # Node.js Tools for Visual Studio
277 | .ntvs_analysis.dat
278 | node_modules/
279 |
280 | # Visual Studio 6 build log
281 | *.plg
282 |
283 | # Visual Studio 6 workspace options file
284 | *.opt
285 |
286 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
287 | *.vbw
288 |
289 | # Visual Studio LightSwitch build output
290 | **/*.HTMLClient/GeneratedArtifacts
291 | **/*.DesktopClient/GeneratedArtifacts
292 | **/*.DesktopClient/ModelManifest.xml
293 | **/*.Server/GeneratedArtifacts
294 | **/*.Server/ModelManifest.xml
295 | _Pvt_Extensions
296 |
297 | # Paket dependency manager
298 | .paket/paket.exe
299 | paket-files/
300 |
301 | # FAKE - F# Make
302 | .fake/
303 |
304 | # CodeRush personal settings
305 | .cr/personal
306 |
307 | # Python Tools for Visual Studio (PTVS)
308 | __pycache__/
309 | *.pyc
310 |
311 | # Cake - Uncomment if you are using it
312 | tools/**
313 | !tools/packages.config
314 |
315 | # Tabs Studio
316 | *.tss
317 |
318 | # Telerik's JustMock configuration file
319 | *.jmconfig
320 |
321 | # BizTalk build output
322 | *.btp.cs
323 | *.btm.cs
324 | *.odx.cs
325 | *.xsd.cs
326 |
327 | # OpenCover UI analysis results
328 | OpenCover/
329 |
330 | # Azure Stream Analytics local run output
331 | ASALocalRun/
332 |
333 | # MSBuild Binary and Structured Log
334 | *.binlog
335 |
336 | # NVidia Nsight GPU debugger configuration file
337 | *.nvuser
338 |
339 | # MFractors (Xamarin productivity tool) working folder
340 | .mfractor/
341 |
342 | # Local History for Visual Studio
343 | .localhistory/
344 |
345 | # BeatPulse healthcheck temp database
346 | healthchecksdb
347 |
348 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
349 | MigrationBackup/
350 |
351 | # Ionide (cross platform F# VS Code tools) working folder
352 | .ionide/
353 |
354 | # ReportGenerator
355 | coverageOutput/
356 | result.xml
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | lucasluizss
4 | true
5 | true
6 | true
7 | latest
8 | en
9 | True
10 |
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## ⚔️ Tyrion
2 |
3 | [](https://dev.azure.com/lucasluizss/Tyrion.CQRS/_build/latest?definitionId=1&branchName=master)
4 | [](https://github.com/lucasluizss/Tyrion.CQRS)
5 | [](https://www.nuget.org/packages/tyrion)
6 | [](https://www.nuget.org/packages/tyrion)
7 | [](https://www.codacy.com/manual/lucasluizss/Tyrion.CQRS?utm_source=github.com&utm_medium=referral&utm_content=lucasluizss/Tyrion.CQRS&utm_campaign=Badge_Grade)
8 |
9 | Tyrion is an implementation of mediator pattern for dotnet
10 |
11 | ## 👨🏽💻 Installing
12 |
13 | - Package Manager
14 |
15 | ```bash
16 | Install-Package Tyrion
17 | ```
18 |
19 | - .Net CLI
20 |
21 | ```bash
22 | dotnet add package Tyrion
23 | ```
24 |
25 | - Pakat CLI
26 |
27 | ```bash
28 | paket add Tyrion
29 | ```
30 |
31 | ## 🧾 Usage
32 |
33 | In your Startup.cs, add Tyrion on your service with some typeof class, for identify the currently assembly project. (Could be any class in your project) like this:
34 |
35 | ```csharp
36 |
37 | services.AddTyrion(typeof(Category));
38 |
39 | ```
40 |
41 | When we talk about mediator everything is about requests... Tyrion is abstract for just one interface, where you will handle with multiple concepts types implementing just the IRequest interface for Commands and Queries and INotification interface when you want send multiple notifications events.
42 |
43 | You must keep it simple, so when you are creating a CommandHandle you have to combine your Command request. That way, Tyrion can find quickly the required implementation.
44 |
45 | Samples of requests bellow:
46 |
47 | ```csharp
48 | public class ProductCommand : IRequest { }
49 |
50 | public class CategoryQuery : IRequest { }
51 |
52 | public class CategoryAddedEvent : INotification { }
53 | ```
54 |
55 | Samples of validation requests bellow (this is an optional implementation):
56 |
57 | ```csharp
58 | public sealed class CategoryCommandValidator : Validator
59 | {
60 | public CategoryCommandValidator()
61 | {
62 | RuleFor(x => x.Name).NotEmpty();
63 | }
64 | }
65 | ```
66 |
67 | Samples of Handlers bellow:
68 |
69 | ```csharp
70 | public sealed class CategoryCommandHandler : IRequestHandler
71 | {
72 | public async Task> Execute(CategoryCommand command)
73 | {
74 | return await Result.SuccessedAsync(new Category());
75 | }
76 | }
77 |
78 | public sealed class CategoryQueryHandler : IRequestHandler
79 | {
80 | public async Task> Execute(CategoryQuery request)
81 | {
82 | return await Result.SuccessedAsync(new Category());
83 | }
84 | }
85 |
86 | public sealed class CategoryNotificationHandler : INotificationHandler
87 | {
88 | public async Task Publish(CategoryAddedEvent notification)
89 | {
90 | await Task.CompletedTask;
91 | }
92 | }
93 | ```
94 |
95 | IRequestHandler an receive one or two generics arguments, the first one is your request (Command, Query, etc) all implementing IRequest and the secound one is you return type if you need.
96 |
97 | Case you implement your request validation (using Validator<> class), Tyrion will handle with the validation and return your errors automaticaly.
98 |
99 | That way we can assunrency that we will receive what we are requiring.
100 |
101 | Tyrion allows you to implement multiple handlers in your application service. Just in case you need keep the same context together.
102 |
103 | Something like this:
104 |
105 | ```csharp
106 | public sealed class ProductCommandHandler : IRequestHandler,
107 | IRequestHandler,
108 | IRequestHandler,
109 | IRequestHandler
110 | {
111 | public async Task> Execute(SaveProductCommand request)
112 | {
113 | return await Result.SuccessedAsync(new Product());
114 | }
115 |
116 | public async Task> Execute(UpdateProductCommand command)
117 | {
118 | return await Result.SuccessedAsync(new Product());
119 | }
120 |
121 | public async Task Execute(RemoveProductCommand request)
122 | {
123 | return await Result.SuccessedAsync(new Product());
124 | }
125 |
126 | public async Task Execute(InativeProductCommand request)
127 | {
128 | return await Result.SuccessedAsync();
129 | }
130 | }
131 | ```
132 |
133 | I hope you enjoy this. I will work to include little improvements!
134 |
135 | ## 🙋🏽♂️ Author
136 |
137 | X: [@lucasluizss](https://x.com/lucasluizss)
138 | Platform: [@lucaslab.dev](https://lucaslab.dev)
139 |
140 | ## 📝 Contributing
141 |
142 | Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
143 |
144 | Please make sure to update tests as appropriate.
145 |
146 | ## ⚖️ License
147 |
148 | [MIT](https://choosealicense.com/licenses/mit/)
149 |
--------------------------------------------------------------------------------
/Tyrion.CQRS.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29613.14
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tyrion.Tests", "src\Tyrion.Tests\Tyrion.Tests.csproj", "{6A667415-0257-412B-843E-B5EE4ACFB76A}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tyrion", "src\Tyrion\Tyrion.csproj", "{14745A2F-0CF4-4EE6-82BF-354F3A39F67D}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {6A667415-0257-412B-843E-B5EE4ACFB76A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {6A667415-0257-412B-843E-B5EE4ACFB76A}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {6A667415-0257-412B-843E-B5EE4ACFB76A}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {6A667415-0257-412B-843E-B5EE4ACFB76A}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {14745A2F-0CF4-4EE6-82BF-354F3A39F67D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {14745A2F-0CF4-4EE6-82BF-354F3A39F67D}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {14745A2F-0CF4-4EE6-82BF-354F3A39F67D}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {14745A2F-0CF4-4EE6-82BF-354F3A39F67D}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {210C3464-543E-4389-A5A1-FBB5546FB249}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | version: 1.0.{build}
2 | pull_requests:
3 | do_not_increment_build_number: true
4 | skip_tags: true
5 | build:
6 | verbosity: minimal
--------------------------------------------------------------------------------
/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | # Starter pipeline
2 | # Start with a minimal pipeline that you can customize to build and deploy your code.
3 | # Add steps that build, run tests, deploy, and more:
4 | # https://aka.ms/yaml
5 |
6 | trigger:
7 | - master
8 |
9 | pool:
10 | vmImage: 'windows-latest'
11 |
12 | steps:
13 | - powershell: .\build.ps1 -Target Coverage
14 | displayName: 'Run Tests & Coverage'
15 |
--------------------------------------------------------------------------------
/src/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucaslab-dev/Tyrion/f287193a1eee57bc63912f76877b9281f34bd6c9/src/.DS_Store
--------------------------------------------------------------------------------
/src/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Lucas Silva
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/Tyrion.Tests/Category/Category.cs:
--------------------------------------------------------------------------------
1 | namespace Tyrion.Tests
2 | {
3 | public class Category { }
4 | }
--------------------------------------------------------------------------------
/src/Tyrion.Tests/Category/CategoryCommand.cs:
--------------------------------------------------------------------------------
1 | namespace Tyrion.Tests
2 | {
3 | public sealed class CategoryCommand : IRequest
4 | {
5 | public string Name { get; set; }
6 | }
7 | }
--------------------------------------------------------------------------------
/src/Tyrion.Tests/Category/CategoryCommandHandler.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace Tyrion.Tests
4 | {
5 | public sealed class CategoryCommandHandler : IRequestHandler
6 | {
7 | public async Task> Execute(CategoryCommand command)
8 | {
9 | return await Result.SuccessAsync(new Category());
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/Tyrion.Tests/Category/CategoryCommandValidator.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation;
2 |
3 | namespace Tyrion.Tests
4 | {
5 | public sealed class CategoryCommandValidator : Validator
6 | {
7 | public CategoryCommandValidator()
8 | {
9 | RuleFor(x => x.Name).NotEmpty();
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/src/Tyrion.Tests/Product/InativeProductCommand.cs:
--------------------------------------------------------------------------------
1 | namespace Tyrion.Tests
2 | {
3 | public sealed class InativeProductCommand : IRequest { }
4 | }
5 |
--------------------------------------------------------------------------------
/src/Tyrion.Tests/Product/LastProductInStockEvent.cs:
--------------------------------------------------------------------------------
1 | namespace Tyrion.Tests
2 | {
3 | public class LastProductInStockEvent : INotification { }
4 | }
5 |
--------------------------------------------------------------------------------
/src/Tyrion.Tests/Product/Product.cs:
--------------------------------------------------------------------------------
1 | namespace Tyrion.Tests
2 | {
3 | public class Product { }
4 | }
5 |
--------------------------------------------------------------------------------
/src/Tyrion.Tests/Product/ProductCommandHandler.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace Tyrion.Tests
4 | {
5 | public sealed class ProductCommandHandler : IRequestHandler,
6 | IRequestHandler,
7 | IRequestHandler,
8 | IRequestHandler
9 | {
10 | public async Task> Execute(SaveProductCommand request)
11 | {
12 | return await Result.SuccessAsync(new Product());
13 | }
14 |
15 | public async Task> Execute(UpdateProductCommand command)
16 | {
17 | return await Result.SuccessAsync(new Product());
18 | }
19 |
20 | public async Task Execute(RemoveProductCommand request)
21 | {
22 | return await Result.SuccessAsync();
23 | }
24 |
25 | public async Task Execute(InativeProductCommand request)
26 | {
27 | return await Result.SuccessAsync();
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Tyrion.Tests/Product/ProductDiscountEmailEvent.cs:
--------------------------------------------------------------------------------
1 | namespace Tyrion.Tests
2 | {
3 | public class ProductDiscountEmailEvent : INotification { }
4 | }
5 |
--------------------------------------------------------------------------------
/src/Tyrion.Tests/Product/ProductGiftEvent.cs:
--------------------------------------------------------------------------------
1 | namespace Tyrion.Tests
2 | {
3 | public class ProductGiftEvent : INotification { }
4 | }
5 |
--------------------------------------------------------------------------------
/src/Tyrion.Tests/Product/ProductNotificationHandler.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace Tyrion.Tests
4 | {
5 | public sealed class ProductNotificationHandler : INotificationHandler,
6 | INotificationHandler,
7 | INotificationHandler
8 | {
9 | public async Task Publish(LastProductInStockEvent request)
10 | {
11 | await Task.CompletedTask.ConfigureAwait(false);
12 | }
13 |
14 | public async Task Publish(ProductGiftEvent request)
15 | {
16 | await Task.CompletedTask.ConfigureAwait(false);
17 | }
18 |
19 | public async Task Publish(ProductDiscountEmailEvent request)
20 | {
21 | await Task.CompletedTask.ConfigureAwait(false);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Tyrion.Tests/Product/RemoveProductCommand.cs:
--------------------------------------------------------------------------------
1 | namespace Tyrion.Tests
2 | {
3 | public sealed class RemoveProductCommand : IRequest { }
4 | }
5 |
--------------------------------------------------------------------------------
/src/Tyrion.Tests/Product/SaveProductCommand.cs:
--------------------------------------------------------------------------------
1 | namespace Tyrion.Tests
2 | {
3 | public sealed class SaveProductCommand : IRequest { }
4 | }
5 |
--------------------------------------------------------------------------------
/src/Tyrion.Tests/Product/UpdateProductCommand.cs:
--------------------------------------------------------------------------------
1 | namespace Tyrion.Tests
2 | {
3 | public sealed class UpdateProductCommand : IRequest { }
4 | }
5 |
--------------------------------------------------------------------------------
/src/Tyrion.Tests/Tyrion.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net7.0
4 | false
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/Tyrion.Tests/TyrionTests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 |
4 | namespace Tyrion.Tests
5 | {
6 | [TestClass]
7 | public class Tests
8 | {
9 | private readonly ITyrion _tyrion;
10 |
11 | public Tests()
12 | {
13 | var services = new ServiceCollection();
14 |
15 | services.AddTyrion(typeof(Category));
16 |
17 | _tyrion = services.BuildServiceProvider().GetRequiredService();
18 | }
19 |
20 | [TestMethod]
21 | public void TestMethodStuff()
22 | {
23 | var command = new CategoryCommand
24 | {
25 | Name = "stuff"
26 | };
27 |
28 | var result = _tyrion.Execute(command).Result;
29 |
30 | Assert.IsTrue(result.Successed);
31 | }
32 |
33 | [TestMethod]
34 | public void TestMethodSaveProduct()
35 | {
36 | var command = new SaveProductCommand();
37 |
38 | var result = _tyrion.Execute(command).Result;
39 |
40 | Assert.IsTrue(result.Successed);
41 | }
42 |
43 | [TestMethod]
44 | public void TestMethodUpdateProduct()
45 | {
46 | var command = new UpdateProductCommand();
47 |
48 | var result = _tyrion.Execute(command).Result;
49 |
50 | Assert.IsTrue(result.Successed);
51 | }
52 |
53 | [TestMethod]
54 | public void TestMethodRemoveProduct()
55 | {
56 | var command = new RemoveProductCommand();
57 |
58 | var result = _tyrion.Execute(command).Result;
59 |
60 | Assert.IsTrue(result.Successed);
61 | }
62 |
63 | [TestMethod]
64 | public void TestMethodInativeProduct()
65 | {
66 | var command = new InativeProductCommand();
67 |
68 | var result = _tyrion.Execute(command).Result;
69 |
70 | Assert.IsTrue(result.Successed);
71 | }
72 |
73 | [TestMethod]
74 | public void TestMethodProductNotification()
75 | {
76 | _tyrion.Publish(new LastProductInStockEvent()).GetAwaiter();
77 | _tyrion.Publish(new ProductGiftEvent()).GetAwaiter();
78 | _tyrion.Publish(new ProductDiscountEmailEvent()).GetAwaiter();
79 | }
80 | }
81 | }
--------------------------------------------------------------------------------
/src/Tyrion/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucaslab-dev/Tyrion/f287193a1eee57bc63912f76877b9281f34bd6c9/src/Tyrion/.DS_Store
--------------------------------------------------------------------------------
/src/Tyrion/Extensions/ServiceCollectionExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using Microsoft.Extensions.DependencyInjection.Extensions;
3 | using System;
4 | using System.Linq;
5 |
6 | namespace Tyrion
7 | {
8 | public static class ServiceCollectionExtensions
9 | {
10 | private static bool IsRequestHandlers(Type type) => type.Is(typeof(IRequestHandler<,>)) || type.Is(typeof(IRequestHandler<>)) || type.Is(typeof(INotificationHandler<>));
11 |
12 | public static void AddTyrion(this IServiceCollection services, Type type)
13 | {
14 | services.AddScoped();
15 | services.AddRequestHandlers(type);
16 | services.AddValidators(type);
17 | }
18 |
19 | private static void AddRequestHandlers(this IServiceCollection services, Type type) => type.Assembly
20 | .GetTypes()
21 | .Where(type => type.GetInterfaces().Any(IsRequestHandlers)).ToList()
22 | .ForEach(type => type.GetInterfaces().Where(IsRequestHandlers).ToList().ForEach(@interface => services.TryAddScoped(@interface, type)));
23 |
24 | private static void AddValidators(this IServiceCollection services, Type type) => type.Assembly
25 | .GetTypes()
26 | .Where(type => type.BaseType.Is(typeof(Validator<>))).ToList()
27 | .ForEach(type => services.TryAddScoped(type.BaseType, type));
28 | }
29 | }
--------------------------------------------------------------------------------
/src/Tyrion/Extensions/TypeExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Tyrion
4 | {
5 | public static class TypeExtensions
6 | {
7 | public static bool Is(this Type type, Type typeCompare) => type.IsGenericType && (type.Name.Equals(typeCompare.Name) || type.GetGenericTypeDefinition() == typeCompare);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/Tyrion/Handlers/INotification.cs:
--------------------------------------------------------------------------------
1 | namespace Tyrion
2 | {
3 | public interface INotification { }
4 | }
5 |
--------------------------------------------------------------------------------
/src/Tyrion/Handlers/INotificationHandler.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace Tyrion
4 | {
5 | public interface INotificationHandler where TRequest : INotification
6 | {
7 | Task Publish(TRequest request);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/Tyrion/Handlers/IRequest.cs:
--------------------------------------------------------------------------------
1 | namespace Tyrion
2 | {
3 | public interface IRequest { }
4 | }
--------------------------------------------------------------------------------
/src/Tyrion/Handlers/IRequestHandler.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace Tyrion
4 | {
5 | public interface IRequestHandler where TRequest : IRequest
6 | {
7 | Task> Execute(TRequest request);
8 | }
9 |
10 | public interface IRequestHandler where TRequest : IRequest
11 | {
12 | Task Execute(TRequest request);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/Tyrion/ITyrion.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace Tyrion
4 | {
5 | public interface ITyrion
6 | {
7 | ///
8 | /// Returns an IResult of TResult where request must be an IRequest.
9 | ///
10 | ///
11 | ///
12 | ///
13 | ///
14 | Task> Execute(TRequest request) where TRequest : IRequest;
15 |
16 | ///
17 | /// Returns a Task. For use when don't require a return.
18 | ///
19 | ///
20 | ///
21 | ///
22 | Task Execute(TRequest request) where TRequest : IRequest;
23 |
24 | ///
25 | /// Publish a notification for all handlers subscribed.
26 | ///
27 | ///
28 | ///
29 | ///
30 | Task Publish(TRequest notification) where TRequest : INotification;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Tyrion/Results/IResult.cs:
--------------------------------------------------------------------------------
1 | namespace Tyrion
2 | {
3 | public interface IResult
4 | {
5 | public bool Successed { get; }
6 | public bool Failed { get; }
7 | public string Message { get; }
8 | }
9 |
10 | public interface IResult : IResult
11 | {
12 | public T Data { get; }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/Tyrion/Results/Result.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace Tyrion
4 | {
5 | public class Result : IResult
6 | {
7 | protected Result() => Successed = true;
8 |
9 | protected Result(string message, bool successed)
10 | {
11 | Successed = successed;
12 | Failed = !successed;
13 | Message = message;
14 | }
15 |
16 | public bool Successed { get; protected set; }
17 |
18 | public bool Failed { get; protected set; }
19 |
20 | public string Message { get; protected set; }
21 |
22 | public static IResult Success() => new Result();
23 |
24 | public static IResult Success(string message) => new Result(message, true);
25 |
26 | public static Task SuccessAsync() => Task.FromResult(Success());
27 |
28 | public static Task SuccessAsync(string message) => Task.FromResult(Success(message));
29 |
30 | public static IResult Fail(string message) => new Result(message, false);
31 |
32 | public static Task FailAsync(string message) => Task.FromResult(Fail(message));
33 | }
34 |
35 | public sealed class Result : Result, IResult
36 | {
37 | private Result() => Successed = true;
38 |
39 | private Result(T data, bool successed)
40 | {
41 | Successed = successed;
42 | Failed = !successed;
43 | Data = data;
44 | }
45 |
46 | private Result(string message, bool successed)
47 | {
48 | Successed = successed;
49 | Failed = !successed;
50 | Message = message;
51 | }
52 |
53 | public T Data { get; }
54 |
55 | public new static IResult Success() => new Result();
56 |
57 | public static IResult Success(T data) => new Result(data, true);
58 |
59 | public static Task> SuccessAsync(T data) => Task.FromResult(Success(data));
60 |
61 | public new static IResult Fail(string message) => new Result(message, false);
62 |
63 | public new static Task> FailAsync(string message) => Task.FromResult(Fail(message));
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/Tyrion/Tyrion.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using System;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace Tyrion
7 | {
8 | public sealed class Tyrion : ITyrion
9 | {
10 | private readonly IServiceProvider _serviceProvider;
11 |
12 | public Tyrion(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider;
13 |
14 | public async Task> Execute(TRequest request) where TRequest : IRequest
15 | {
16 | var validator = await ValidateRequestAsync(request);
17 |
18 | if (validator.Failed)
19 | {
20 | return Result.Fail(validator.Message);
21 | }
22 |
23 | var service = _serviceProvider.GetService>();
24 |
25 | if (service == default)
26 | {
27 | throw new ArgumentException($"Class implementing {nameof(IRequestHandler)} not found or not implemented!");
28 | }
29 |
30 | return await service.Execute(request).ConfigureAwait(false);
31 | }
32 |
33 | public async Task Execute(TRequest request) where TRequest : IRequest
34 | {
35 | var validator = await ValidateRequestAsync(request);
36 |
37 | if (validator.Failed)
38 | {
39 | return Result.Fail(validator.Message);
40 | }
41 |
42 | var service = _serviceProvider.GetService>();
43 |
44 | if (service == default)
45 | {
46 | throw new ArgumentException($"Class implementing {nameof(IRequestHandler)} not found or not implemented!");
47 | }
48 |
49 | return await service.Execute(request).ConfigureAwait(false);
50 | }
51 |
52 | public async Task Publish(TRequest notification) where TRequest : INotification
53 | {
54 | var services = _serviceProvider.GetServices>();
55 |
56 | if (!services.Any())
57 | {
58 | throw new ArgumentException($"No class implementing {nameof(INotificationHandler)} not found or not implemented!");
59 | }
60 |
61 | await Task.WhenAll(services.Select(service => service.Publish(notification))).ConfigureAwait(false);
62 | }
63 |
64 | private async Task ValidateRequestAsync(TRequest request) where TRequest : IRequest
65 | {
66 | var validator = _serviceProvider.GetService>();
67 |
68 | if (validator == default)
69 | {
70 | return await Result.SuccessAsync();
71 | }
72 |
73 | return await validator.ValidateAsync(request);
74 | }
75 | }
76 | }
--------------------------------------------------------------------------------
/src/Tyrion/Tyrion.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netstandard2.0
4 |
5 | true
6 | Lucas Silva
7 | lucaslab.dev
8 | Tyrion is a mediator implementation for dotnet
9 | https://github.com/lucasluizss/Tyrion.CQRS
10 | mediator;cqrs;dotnet;events;notification
11 | Tyrion
12 | Tyrion.CQRS
13 | LICENSE
14 | 1.1.5
15 |
16 | In this new release, we add some resources, including:
17 | - Compatibility with dotnet standard applications
18 |
19 | https://github.com/lucasluizss/Tyrion.CQRS
20 | tyrion.png
21 |
22 |
23 |
24 |
25 | True
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/Tyrion/Validators/Validator.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation;
2 | using System.Threading.Tasks;
3 |
4 | namespace Tyrion
5 | {
6 | public abstract class Validator : AbstractValidator where T : IRequest
7 | {
8 | private string Message { get; set; }
9 |
10 | public new IResult Validate(T instance)
11 | {
12 | if (Equals(instance, default(T)))
13 | {
14 | return Result.Fail(Message ?? string.Empty);
15 | }
16 |
17 | var result = base.Validate(instance);
18 |
19 | return result.IsValid ? Result.Success() : Result.Fail(Message ?? result.ToString());
20 | }
21 |
22 | public Task ValidateAsync(T instance) => Task.FromResult(Validate(instance));
23 |
24 | public void CustomMessage(string message) => Message = message;
25 | }
26 | }
--------------------------------------------------------------------------------