├── .github
├── dependabot.yml
└── workflows
│ ├── build-and-dockerize.yml
│ ├── codeql.yml
│ └── docker.yml
├── .gitignore
├── .mergify.yml
├── .vscode
└── settings.json
├── BervProject.WebApi.Boilerplate.AppHost
├── BervProject.WebApi.Boilerplate.AppHost.csproj
├── Program.cs
├── appsettings.Development.json
└── appsettings.json
├── BervProject.WebApi.Boilerplate.MigrationService
├── BervProject.WebApi.Boilerplate.MigrationService.csproj
├── Program.cs
├── Worker.cs
├── appsettings.Development.json
└── appsettings.json
├── BervProject.WebApi.Boilerplate.ServiceDefaults
├── BervProject.WebApi.Boilerplate.ServiceDefaults.csproj
└── Extensions.cs
├── BervProject.WebApi.Boilerplate.ndproj
├── BervProject.WebApi.Boilerplate.sln
├── BervProject.WebApi.Boilerplate
├── .gitignore
├── BervProject.WebApi.Boilerplate.csproj
├── ConfigModel
│ ├── AWSConfiguration.cs
│ └── AzureConfiguration.cs
├── Controllers
│ ├── AWSS3Controller.cs
│ ├── BlobController.cs
│ ├── CronController.cs
│ ├── DynamoController.cs
│ ├── EmailController.cs
│ ├── ErrorController.cs
│ ├── NoteController.cs
│ ├── ServiceBusSenderController.cs
│ ├── StorageQueueController.cs
│ └── WeatherForecastController.cs
├── Entities
│ ├── Book.cs
│ ├── Note.cs
│ └── Publisher.cs
├── EntityFramework
│ └── BoilerplateDbContext.cs
├── Extensions
│ ├── SetupAWSExtension.cs
│ └── SetupAzureExtension.cs
├── Migrations
│ ├── 20210118042709_NewBookDb.Designer.cs
│ ├── 20210118042709_NewBookDb.cs
│ └── BoilerplateDbContextModelSnapshot.cs
├── Models
│ ├── EmailSendRequest.cs
│ ├── MessageData.cs
│ ├── Request
│ │ └── UploadFile.cs
│ ├── Response
│ │ └── MessageSenderResponse.cs
│ └── WeatherForecast.cs
├── NLog.config
├── Program.cs
├── Services
│ ├── AWS
│ │ ├── AWSS3Service.cs
│ │ ├── DynamoDbServices.cs
│ │ ├── EmailService.cs
│ │ ├── IAWSS3Service.cs
│ │ ├── IDynamoDbServices.cs
│ │ └── IEmailService.cs
│ ├── Azure
│ │ ├── AzureQueueServices.cs
│ │ ├── AzureStorageQueueService.cs
│ │ ├── AzureTableStorageService.cs
│ │ ├── BlobService.cs
│ │ ├── IAzureQueueServices.cs
│ │ ├── IAzureStorageQueueService.cs
│ │ ├── IAzureTableStorageService.cs
│ │ ├── IBlobService.cs
│ │ ├── IServiceBusQueueConsumer.cs
│ │ ├── IServiceBusTopicSubscription.cs
│ │ ├── ITopicServices.cs
│ │ ├── ServiceBusQueueConsumer.cs
│ │ ├── ServiceBusTopicSubscription.cs
│ │ └── TopicServices.cs
│ ├── CronService.cs
│ ├── ICronService.cs
│ ├── IProcessData.cs
│ └── ProcessData.cs
├── appsettings.Development.json
└── appsettings.json
├── BervProject.WebApi.Integration.Test
├── BervProject.WebApi.Integration.Test.csproj
├── BlobControllerTest.cs
├── Collections
│ └── WebAppCollection.cs
├── CronControllerTest.cs
├── Docs
│ └── test.txt
├── ErrorControllerTest.cs
├── Fixtures
│ └── WebAppFixture.cs
├── HealthCheckTest.cs
├── NoteControllerTest.cs
├── StorageQueueControllerTest.cs
├── Usings.cs
└── WeatherForecastControllerTest.cs
├── BervProject.WebApi.Test
├── BervProject.WebApi.Test.csproj
├── Services
│ ├── AWS
│ │ ├── AWSS3ServiceTest.cs
│ │ ├── DynamoDbServicesTest.cs
│ │ └── EmailServiceTest.cs
│ ├── Azure
│ │ ├── AzureQueueServicesTest.cs
│ │ ├── AzureStorageQueueServiceTest.cs
│ │ ├── BlobServiceTest.cs
│ │ └── TopicServiceTest.cs
│ ├── CronServiceTest.cs
│ └── ProcessDataTest.cs
└── WeatherForecastTest.cs
├── Dockerfile
├── LICENSE
├── README.md
└── azure-pipelines.yml
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: nuget
4 | directory: "/"
5 | schedule:
6 | interval: daily
7 | time: "08:00"
8 | timezone: Asia/Jakarta
9 | open-pull-requests-limit: 100
10 | groups:
11 | awssdk:
12 | patterns:
13 | - "AWSSDK*"
14 | azure:
15 | patterns:
16 | - "Azure*"
17 | hangfire:
18 | patterns:
19 | - "Hangfire*"
20 | nlog:
21 | patterns:
22 | - "NLog*"
23 |
24 | - package-ecosystem: github-actions
25 | directory: "/"
26 | schedule:
27 | interval: weekly
28 | day: saturday
29 | time: "08:00"
30 | timezone: Asia/Jakarta
31 | open-pull-requests-limit: 100
32 | reviewers:
33 | - berviantoleo
34 | assignees:
35 | - berviantoleo
36 |
37 | - package-ecosystem: docker
38 | directory: "/"
39 | schedule:
40 | interval: weekly
41 | day: saturday
42 | time: "08:00"
43 | timezone: Asia/Jakarta
44 | open-pull-requests-limit: 100
45 | reviewers:
46 | - berviantoleo
47 | assignees:
48 | - berviantoleo
49 |
--------------------------------------------------------------------------------
/.github/workflows/build-and-dockerize.yml:
--------------------------------------------------------------------------------
1 | name: Build .NET
2 | on:
3 | push:
4 | branches: [ main ]
5 | pull_request:
6 | branches: [ main ]
7 | env:
8 | ConnectionStrings__BoilerplateConnectionString: "Host=localhost;Database=testdb;Username=postgres;Password=postgres"
9 | jobs:
10 | build:
11 | # Service containers to run with `container-job`
12 | services:
13 | # Label used to access the service container
14 | postgres:
15 | # Docker Hub image
16 | image: postgres:17-alpine
17 | ports:
18 | - 5432:5432
19 | # Provide the password for postgres
20 | env:
21 | POSTGRES_PASSWORD: postgres
22 | POSTGRES_DB: testdb
23 | # Set health checks to wait until postgres has started
24 | options: >-
25 | --health-cmd pg_isready
26 | --health-interval 10s
27 | --health-timeout 5s
28 | --health-retries 5
29 | azurite:
30 | image: mcr.microsoft.com/azure-storage/azurite
31 | ports:
32 | - 10000:10000
33 | - 10001:10001
34 | - 10002:10002
35 | runs-on: ubuntu-24.04
36 | steps:
37 | - uses: actions/checkout@v4
38 | - name: Setup .NET Core
39 | uses: actions/setup-dotnet@v4
40 | with:
41 | dotnet-version: '9.0.x'
42 | - name: Install dependencies
43 | run: dotnet restore
44 | - name: Build
45 | run: dotnet build --configuration Release --no-restore
46 | - name: Migrate DB
47 | run: |
48 | dotnet tool install --global dotnet-ef
49 | dotnet tool restore
50 | dotnet ef database update --startup-project BervProject.WebApi.Boilerplate --project BervProject.WebApi.Boilerplate
51 | - name: Test
52 | run: dotnet test --configuration Release --no-restore --no-build --verbosity normal --collect:"XPlat Code Coverage"
53 | - name: Report Codecov
54 | uses: codecov/codecov-action@v5
55 |
--------------------------------------------------------------------------------
/.github/workflows/codeql.yml:
--------------------------------------------------------------------------------
1 | name: "CodeQL"
2 | on:
3 | push:
4 | branches: [ main ]
5 | pull_request:
6 | # The branches below must be a subset of the branches above
7 | branches: [ main ]
8 | schedule:
9 | - cron: '30 1 * * 6'
10 | jobs:
11 | codeql:
12 | name: Analyze
13 | permissions:
14 | actions: read
15 | contents: read
16 | security-events: write
17 | runs-on: ubuntu-24.04
18 | steps:
19 | - uses: actions/checkout@v4
20 | - name: Initialize CodeQL
21 | uses: github/codeql-action/init@v3
22 | with:
23 | languages: csharp
24 | - name: Setup .NET Core
25 | uses: actions/setup-dotnet@v4
26 | with:
27 | dotnet-version: '9.0.x'
28 | dotnet-quality: 'preview'
29 | - name: Autobuild
30 | uses: github/codeql-action/autobuild@v3
31 | - name: Perform CodeQL Analysis
32 | uses: github/codeql-action/analyze@v3
33 |
--------------------------------------------------------------------------------
/.github/workflows/docker.yml:
--------------------------------------------------------------------------------
1 | name: Dockerize
2 | on:
3 | push:
4 | branches: [ main ]
5 | tags:
6 | - v*
7 | pull_request:
8 | branches: [ main ]
9 | env:
10 | IMAGE_NAME: netcoreboilerplate
11 | jobs:
12 | build-docker-test:
13 | runs-on: ubuntu-24.04
14 | if: github.event_name == 'pull_request'
15 | steps:
16 | - uses: actions/checkout@v4
17 | - uses: hadolint/hadolint-action@v3.1.0
18 | name: Lint Dockerfile
19 | with:
20 | dockerfile: Dockerfile
21 | failure-threshold: error
22 | - name: Build Image
23 | run: docker build . -t $IMAGE_NAME
24 | - name: Run Trivy vulnerability scanner
25 | uses: aquasecurity/trivy-action@master
26 | with:
27 | image-ref: ${{ env.IMAGE_NAME }}
28 | format: 'sarif'
29 | output: 'trivy-results.sarif'
30 | - name: Upload Trivy scan results to GitHub Security tab
31 | uses: github/codeql-action/upload-sarif@v3
32 | with:
33 | sarif_file: 'trivy-results.sarif'
34 | build-push-docker:
35 | runs-on: ubuntu-24.04
36 | if: github.event_name == 'push'
37 | steps:
38 | - uses: actions/checkout@v4
39 | - name: Set up QEMU
40 | uses: docker/setup-qemu-action@v3
41 | - name: Set up Docker Buildx
42 | uses: docker/setup-buildx-action@v3
43 | with:
44 | platforms: linux/amd64,linux/arm64
45 | - name: Log in to Docker Hub
46 | uses: docker/login-action@v3
47 | with:
48 | username: ${{ secrets.DOCKER_USERNAME }}
49 | password: ${{ secrets.DOCKER_TOKEN }}
50 | - name: Log in to the Container registry
51 | uses: docker/login-action@v3
52 | with:
53 | registry: ghcr.io
54 | username: ${{ github.actor }}
55 | password: ${{ secrets.GITHUB_TOKEN }}
56 | - name: Extract metadata (tags, labels) for Docker
57 | id: meta
58 | uses: docker/metadata-action@v5
59 | with:
60 | images: |
61 | bervproject/${{ env.IMAGE_NAME }}
62 | ghcr.io/${{ github.repository }}
63 | - name: Build and push Docker images
64 | uses: docker/build-push-action@v6
65 | with:
66 | context: .
67 | push: true
68 | tags: ${{ steps.meta.outputs.tags }}
69 | labels: ${{ steps.meta.outputs.labels }}
70 |
--------------------------------------------------------------------------------
/.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 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015/2017 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # Visual Studio 2017 auto generated files
33 | Generated\ Files/
34 |
35 | # MSTest test Results
36 | [Tt]est[Rr]esult*/
37 | [Bb]uild[Ll]og.*
38 |
39 | # NUNIT
40 | *.VisualState.xml
41 | TestResult.xml
42 |
43 | # Build Results of an ATL Project
44 | [Dd]ebugPS/
45 | [Rr]eleasePS/
46 | dlldata.c
47 |
48 | # Benchmark Results
49 | BenchmarkDotNet.Artifacts/
50 |
51 | # .NET Core
52 | project.lock.json
53 | project.fragment.lock.json
54 | artifacts/
55 | **/Properties/launchSettings.json
56 |
57 | # StyleCop
58 | StyleCopReport.xml
59 |
60 | # Files built by Visual Studio
61 | *_i.c
62 | *_p.c
63 | *_i.h
64 | *.ilk
65 | *.meta
66 | *.obj
67 | *.iobj
68 | *.pch
69 | *.pdb
70 | *.ipdb
71 | *.pgc
72 | *.pgd
73 | *.rsp
74 | *.sbr
75 | *.tlb
76 | *.tli
77 | *.tlh
78 | *.tmp
79 | *.tmp_proj
80 | *.log
81 | *.vspscc
82 | *.vssscc
83 | .builds
84 | *.pidb
85 | *.svclog
86 | *.scc
87 |
88 | # Chutzpah Test files
89 | _Chutzpah*
90 |
91 | # Visual C++ cache files
92 | ipch/
93 | *.aps
94 | *.ncb
95 | *.opendb
96 | *.opensdf
97 | *.sdf
98 | *.cachefile
99 | *.VC.db
100 | *.VC.VC.opendb
101 |
102 | # Visual Studio profiler
103 | *.psess
104 | *.vsp
105 | *.vspx
106 | *.sap
107 |
108 | # Visual Studio Trace Files
109 | *.e2e
110 |
111 | # TFS 2012 Local Workspace
112 | $tf/
113 |
114 | # Guidance Automation Toolkit
115 | *.gpState
116 |
117 | # ReSharper is a .NET coding add-in
118 | _ReSharper*/
119 | *.[Rr]e[Ss]harper
120 | *.DotSettings.user
121 |
122 | # JustCode is a .NET coding add-in
123 | .JustCode
124 |
125 | # TeamCity is a build add-in
126 | _TeamCity*
127 |
128 | # DotCover is a Code Coverage Tool
129 | *.dotCover
130 |
131 | # AxoCover is a Code Coverage Tool
132 | .axoCover/*
133 | !.axoCover/settings.json
134 |
135 | # Visual Studio code coverage results
136 | *.coverage
137 | *.coveragexml
138 |
139 | # NCrunch
140 | _NCrunch_*
141 | .*crunch*.local.xml
142 | nCrunchTemp_*
143 |
144 | # MightyMoose
145 | *.mm.*
146 | AutoTest.Net/
147 |
148 | # Web workbench (sass)
149 | .sass-cache/
150 |
151 | # Installshield output folder
152 | [Ee]xpress/
153 |
154 | # DocProject is a documentation generator add-in
155 | DocProject/buildhelp/
156 | DocProject/Help/*.HxT
157 | DocProject/Help/*.HxC
158 | DocProject/Help/*.hhc
159 | DocProject/Help/*.hhk
160 | DocProject/Help/*.hhp
161 | DocProject/Help/Html2
162 | DocProject/Help/html
163 |
164 | # Click-Once directory
165 | publish/
166 |
167 | # Publish Web Output
168 | *.[Pp]ublish.xml
169 | *.azurePubxml
170 | # Note: Comment the next line if you want to checkin your web deploy settings,
171 | # but database connection strings (with potential passwords) will be unencrypted
172 | *.pubxml
173 | *.publishproj
174 |
175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
176 | # checkin your Azure Web App publish settings, but sensitive information contained
177 | # in these scripts will be unencrypted
178 | PublishScripts/
179 |
180 | # NuGet Packages
181 | *.nupkg
182 | # The packages folder can be ignored because of Package Restore
183 | **/[Pp]ackages/*
184 | # except build/, which is used as an MSBuild target.
185 | !**/[Pp]ackages/build/
186 | # Uncomment if necessary however generally it will be regenerated when needed
187 | #!**/[Pp]ackages/repositories.config
188 | # NuGet v3's project.json files produces more ignorable files
189 | *.nuget.props
190 | *.nuget.targets
191 |
192 | # Microsoft Azure Build Output
193 | csx/
194 | *.build.csdef
195 |
196 | # Microsoft Azure Emulator
197 | ecf/
198 | rcf/
199 |
200 | # Windows Store app package directories and files
201 | AppPackages/
202 | BundleArtifacts/
203 | Package.StoreAssociation.xml
204 | _pkginfo.txt
205 | *.appx
206 |
207 | # Visual Studio cache files
208 | # files ending in .cache can be ignored
209 | *.[Cc]ache
210 | # but keep track of directories ending in .cache
211 | !*.[Cc]ache/
212 |
213 | # Others
214 | ClientBin/
215 | ~$*
216 | *~
217 | *.dbmdl
218 | *.dbproj.schemaview
219 | *.jfm
220 | *.pfx
221 | *.publishsettings
222 | orleans.codegen.cs
223 |
224 | # Including strong name files can present a security risk
225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
226 | #*.snk
227 |
228 | # Since there are multiple workflows, uncomment next line to ignore bower_components
229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
230 | #bower_components/
231 |
232 | # RIA/Silverlight projects
233 | Generated_Code/
234 |
235 | # Backup & report files from converting an old project file
236 | # to a newer Visual Studio version. Backup files are not needed,
237 | # because we have git ;-)
238 | _UpgradeReport_Files/
239 | Backup*/
240 | UpgradeLog*.XML
241 | UpgradeLog*.htm
242 | ServiceFabricBackup/
243 | *.rptproj.bak
244 |
245 | # SQL Server files
246 | *.mdf
247 | *.ldf
248 | *.ndf
249 |
250 | # Business Intelligence projects
251 | *.rdl.data
252 | *.bim.layout
253 | *.bim_*.settings
254 | *.rptproj.rsuser
255 |
256 | # Microsoft Fakes
257 | FakesAssemblies/
258 |
259 | # GhostDoc plugin setting file
260 | *.GhostDoc.xml
261 |
262 | # Node.js Tools for Visual Studio
263 | .ntvs_analysis.dat
264 | node_modules/
265 |
266 | # Visual Studio 6 build log
267 | *.plg
268 |
269 | # Visual Studio 6 workspace options file
270 | *.opt
271 |
272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
273 | *.vbw
274 |
275 | # Visual Studio LightSwitch build output
276 | **/*.HTMLClient/GeneratedArtifacts
277 | **/*.DesktopClient/GeneratedArtifacts
278 | **/*.DesktopClient/ModelManifest.xml
279 | **/*.Server/GeneratedArtifacts
280 | **/*.Server/ModelManifest.xml
281 | _Pvt_Extensions
282 |
283 | # Paket dependency manager
284 | .paket/paket.exe
285 | paket-files/
286 |
287 | # FAKE - F# Make
288 | .fake/
289 |
290 | # JetBrains Rider
291 | .idea/
292 | *.sln.iml
293 |
294 | # CodeRush
295 | .cr/
296 |
297 | # Python Tools for Visual Studio (PTVS)
298 | __pycache__/
299 | *.pyc
300 |
301 | # Cake - Uncomment if you are using it
302 | # tools/**
303 | # !tools/packages.config
304 |
305 | # Tabs Studio
306 | *.tss
307 |
308 | # Telerik's JustMock configuration file
309 | *.jmconfig
310 |
311 | # BizTalk build output
312 | *.btp.cs
313 | *.btm.cs
314 | *.odx.cs
315 | *.xsd.cs
316 |
317 | # OpenCover UI analysis results
318 | OpenCover/
319 |
320 | # Azure Stream Analytics local run output
321 | ASALocalRun/
322 |
323 | # MSBuild Binary and Structured Log
324 | *.binlog
325 |
326 | # NVidia Nsight GPU debugger configuration file
327 | *.nvuser
328 |
329 | # MFractors (Xamarin productivity tool) working folder
330 | .mfractor/
331 | /NDependOut
332 |
--------------------------------------------------------------------------------
/.mergify.yml:
--------------------------------------------------------------------------------
1 | pull_request_rules:
2 | - name: automatic merge for Dependabot pull requests
3 | conditions:
4 | - author=dependabot[bot]
5 | actions:
6 | merge:
7 | method: squash
8 | review:
9 | type: APPROVE
10 | message: Automatically approving dependabot
11 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "yaml.customTags": [
3 | "!And",
4 | "!And sequence",
5 | "!If",
6 | "!If sequence",
7 | "!Not",
8 | "!Not sequence",
9 | "!Equals",
10 | "!Equals sequence",
11 | "!Or",
12 | "!Or sequence",
13 | "!FindInMap",
14 | "!FindInMap sequence",
15 | "!Base64",
16 | "!Join",
17 | "!Join sequence",
18 | "!Cidr",
19 | "!Ref",
20 | "!Sub",
21 | "!Sub sequence",
22 | "!GetAtt",
23 | "!GetAZs",
24 | "!ImportValue",
25 | "!ImportValue sequence",
26 | "!Select",
27 | "!Select sequence",
28 | "!Split",
29 | "!Split sequence"
30 | ]
31 | }
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate.AppHost/BervProject.WebApi.Boilerplate.AppHost.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Exe
6 | net9.0
7 | enable
8 | enable
9 | true
10 | 0f1966e4-7b2b-4a28-a9b6-8198aab433ec
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate.AppHost/Program.cs:
--------------------------------------------------------------------------------
1 | var builder = DistributedApplication.CreateBuilder(args);
2 |
3 | var cache = builder.AddRedis("cache").WithRedisInsight();
4 | var postgres = builder.AddPostgres("postgres").WithPgAdmin();
5 | var postgresdb = postgres.AddDatabase("postgresdb");
6 | var serviceBus = builder.AddAzureServiceBus("messaging").RunAsEmulator();
7 | var storage = builder.AddAzureStorage("storage").RunAsEmulator();
8 | var blobs = storage.AddBlobs("blobs");
9 | var queues = storage.AddQueues("queues");
10 | var tables = storage.AddTables("tables");
11 |
12 | var migration = builder.AddProject("migrations")
13 | .WithReference(postgresdb, connectionName: "BoilerplateConnectionString")
14 | .WithExplicitStart();
15 |
16 | builder.AddProject("apiservice")
17 | .WithHttpEndpoint()
18 | .WithReference(cache, connectionName: "Redis")
19 | .WithReference(postgresdb, connectionName: "BoilerplateConnectionString")
20 | .WithReference(blobs, connectionName: "AzureStorageBlob")
21 | .WithReference(queues, connectionName: "AzureStorageQueue")
22 | .WithReference(tables, connectionName: "AzureStorageTable")
23 | .WithReference(serviceBus, connectionName: "AzureServiceBus")
24 | .WaitFor(cache)
25 | .WaitFor(postgresdb)
26 | .WaitFor(blobs)
27 | .WaitFor(queues)
28 | .WaitFor(tables)
29 | .WaitFor(serviceBus)
30 | .WaitForCompletion(migration);
31 |
32 | builder.Build().Run();
33 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate.AppHost/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate.AppHost/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning",
6 | "Aspire.Hosting.Dcp": "Warning"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate.MigrationService/BervProject.WebApi.Boilerplate.MigrationService.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | enable
6 | enable
7 | dotnet-BervProject.WebApi.Boilerplate.MigrationService-02d1add9-9cd8-4b0e-96ab-9dedc82c871c
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate.MigrationService/Program.cs:
--------------------------------------------------------------------------------
1 | using BervProject.WebApi.Boilerplate.EntityFramework;
2 | using BervProject.WebApi.Boilerplate.MigrationService;
3 |
4 | var builder = Host.CreateApplicationBuilder(args);
5 |
6 | builder.AddServiceDefaults();
7 |
8 | builder.Services.AddHostedService();
9 |
10 | builder.Services.AddOpenTelemetry()
11 | .WithTracing(tracing => tracing.AddSource(Worker.ActivitySourceName));
12 | builder.AddNpgsqlDbContext("BoilerplateConnectionString");
13 |
14 | var host = builder.Build();
15 | host.Run();
16 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate.MigrationService/Worker.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using BervProject.WebApi.Boilerplate.EntityFramework;
3 | using Microsoft.EntityFrameworkCore;
4 |
5 | namespace BervProject.WebApi.Boilerplate.MigrationService;
6 |
7 | public class Worker : BackgroundService
8 | {
9 | public const string ActivitySourceName = "Migrations";
10 | private static readonly ActivitySource SActivitySource = new(ActivitySourceName);
11 |
12 | private readonly IServiceProvider _serviceProvider;
13 | private readonly IHostApplicationLifetime _hostApplicationLifetime;
14 |
15 | public Worker(IServiceProvider serviceProvider,
16 | IHostApplicationLifetime hostApplicationLifetime)
17 | {
18 | _serviceProvider = serviceProvider;
19 | _hostApplicationLifetime = hostApplicationLifetime;
20 | }
21 |
22 | protected override async Task ExecuteAsync(CancellationToken cancellationToken)
23 | {
24 | using var activity = SActivitySource.StartActivity("Migrating database", ActivityKind.Client);
25 |
26 | try
27 | {
28 | using var scope = _serviceProvider.CreateScope();
29 | var dbContext = scope.ServiceProvider.GetRequiredService();
30 |
31 | await RunMigrationAsync(dbContext, cancellationToken);
32 | }
33 | catch (Exception ex)
34 | {
35 | activity?.AddException(ex);
36 | throw;
37 | }
38 |
39 | _hostApplicationLifetime.StopApplication();
40 | }
41 |
42 | private static async Task RunMigrationAsync(BoilerplateDbContext dbContext, CancellationToken cancellationToken)
43 | {
44 | var strategy = dbContext.Database.CreateExecutionStrategy();
45 | await strategy.ExecuteAsync(async () =>
46 | {
47 | // Run migration in a transaction to avoid partial migration if it fails.
48 | await dbContext.Database.MigrateAsync(cancellationToken);
49 | });
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate.MigrationService/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.Hosting.Lifetime": "Information"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate.MigrationService/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.Hosting.Lifetime": "Information"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate.ServiceDefaults/BervProject.WebApi.Boilerplate.ServiceDefaults.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | enable
6 | enable
7 | true
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate.ServiceDefaults/Extensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Microsoft.AspNetCore.Diagnostics.HealthChecks;
3 | using Microsoft.Extensions.DependencyInjection;
4 | using Microsoft.Extensions.Diagnostics.HealthChecks;
5 | using Microsoft.Extensions.Logging;
6 | using Microsoft.Extensions.ServiceDiscovery;
7 | using OpenTelemetry;
8 | using OpenTelemetry.Metrics;
9 | using OpenTelemetry.Trace;
10 |
11 | namespace Microsoft.Extensions.Hosting;
12 |
13 | // Adds common .NET Aspire services: service discovery, resilience, health checks, and OpenTelemetry.
14 | // This project should be referenced by each service project in your solution.
15 | // To learn more about using this project, see https://aka.ms/dotnet/aspire/service-defaults
16 | public static class Extensions
17 | {
18 | public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder)
19 | {
20 | builder.ConfigureOpenTelemetry();
21 |
22 | builder.AddDefaultHealthChecks();
23 |
24 | builder.Services.AddServiceDiscovery();
25 |
26 | builder.Services.ConfigureHttpClientDefaults(http =>
27 | {
28 | // Turn on resilience by default
29 | http.AddStandardResilienceHandler();
30 |
31 | // Turn on service discovery by default
32 | http.AddServiceDiscovery();
33 | });
34 |
35 | // Uncomment the following to restrict the allowed schemes for service discovery.
36 | // builder.Services.Configure(options =>
37 | // {
38 | // options.AllowedSchemes = ["https"];
39 | // });
40 |
41 | return builder;
42 | }
43 |
44 | public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicationBuilder builder)
45 | {
46 | builder.Logging.AddOpenTelemetry(logging =>
47 | {
48 | logging.IncludeFormattedMessage = true;
49 | logging.IncludeScopes = true;
50 | });
51 |
52 | builder.Services.AddOpenTelemetry()
53 | .WithMetrics(metrics =>
54 | {
55 | metrics.AddAspNetCoreInstrumentation()
56 | .AddHttpClientInstrumentation()
57 | .AddRuntimeInstrumentation();
58 | })
59 | .WithTracing(tracing =>
60 | {
61 | tracing.AddAspNetCoreInstrumentation()
62 | // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package)
63 | //.AddGrpcClientInstrumentation()
64 | .AddHttpClientInstrumentation();
65 | });
66 |
67 | builder.AddOpenTelemetryExporters();
68 |
69 | return builder;
70 | }
71 |
72 | private static IHostApplicationBuilder AddOpenTelemetryExporters(this IHostApplicationBuilder builder)
73 | {
74 | var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);
75 |
76 | if (useOtlpExporter)
77 | {
78 | builder.Services.AddOpenTelemetry().UseOtlpExporter();
79 | }
80 |
81 | // Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package)
82 | //if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"]))
83 | //{
84 | // builder.Services.AddOpenTelemetry()
85 | // .UseAzureMonitor();
86 | //}
87 |
88 | return builder;
89 | }
90 |
91 | public static IHostApplicationBuilder AddDefaultHealthChecks(this IHostApplicationBuilder builder)
92 | {
93 | builder.Services.AddHealthChecks()
94 | // Add a default liveness check to ensure app is responsive
95 | .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]);
96 |
97 | return builder;
98 | }
99 |
100 | public static WebApplication MapDefaultEndpoints(this WebApplication app)
101 | {
102 | // Adding health checks endpoints to applications in non-development environments has security implications.
103 | // See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments.
104 | if (app.Environment.IsDevelopment())
105 | {
106 | // All health checks must pass for app to be considered ready to accept traffic after starting
107 | app.MapHealthChecks("/health");
108 |
109 | // Only health checks tagged with the "live" tag must pass for app to be considered alive
110 | app.MapHealthChecks("/alive", new HealthCheckOptions
111 | {
112 | Predicate = r => r.Tags.Contains("live")
113 | });
114 | }
115 |
116 | return app;
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.0.31903.59
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BervProject.WebApi.Boilerplate", "BervProject.WebApi.Boilerplate\BervProject.WebApi.Boilerplate.csproj", "{61F9CED4-DF01-40F5-A126-DE9F73C7AA89}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BervProject.WebApi.Test", "BervProject.WebApi.Test\BervProject.WebApi.Test.csproj", "{CE1B1BF2-9EF2-4C07-902F-817D81EFD22E}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CB53F077-669D-465F-A871-642F25CC3194}"
11 | ProjectSection(SolutionItems) = preProject
12 | azure-pipelines.yml = azure-pipelines.yml
13 | .github\workflows\build-and-dockerize.yml = .github\workflows\build-and-dockerize.yml
14 | .github\workflows\codeql.yml = .github\workflows\codeql.yml
15 | .github\dependabot.yml = .github\dependabot.yml
16 | Dockerfile = Dockerfile
17 | README.md = README.md
18 | EndProjectSection
19 | EndProject
20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BervProject.WebApi.Integration.Test", "BervProject.WebApi.Integration.Test\BervProject.WebApi.Integration.Test.csproj", "{B1139AC3-3DC2-453D-9A72-9C7196F9759C}"
21 | EndProject
22 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BervProject.WebApi.Boilerplate.AppHost", "BervProject.WebApi.Boilerplate.AppHost\BervProject.WebApi.Boilerplate.AppHost.csproj", "{D6E4407A-586B-4D75-A5F7-5AC9E7016614}"
23 | EndProject
24 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BervProject.WebApi.Boilerplate.ServiceDefaults", "BervProject.WebApi.Boilerplate.ServiceDefaults\BervProject.WebApi.Boilerplate.ServiceDefaults.csproj", "{3E0AA90A-F50F-4226-8236-947B6DC82BCC}"
25 | EndProject
26 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BervProject.WebApi.Boilerplate.MigrationService", "BervProject.WebApi.Boilerplate.MigrationService\BervProject.WebApi.Boilerplate.MigrationService.csproj", "{94B60493-45E4-4437-9155-3D30DFBFB66A}"
27 | EndProject
28 | Global
29 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
30 | Debug|Any CPU = Debug|Any CPU
31 | Debug|x64 = Debug|x64
32 | Debug|x86 = Debug|x86
33 | Release|Any CPU = Release|Any CPU
34 | Release|x64 = Release|x64
35 | Release|x86 = Release|x86
36 | EndGlobalSection
37 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
38 | {61F9CED4-DF01-40F5-A126-DE9F73C7AA89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 | {61F9CED4-DF01-40F5-A126-DE9F73C7AA89}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 | {61F9CED4-DF01-40F5-A126-DE9F73C7AA89}.Debug|x64.ActiveCfg = Debug|Any CPU
41 | {61F9CED4-DF01-40F5-A126-DE9F73C7AA89}.Debug|x64.Build.0 = Debug|Any CPU
42 | {61F9CED4-DF01-40F5-A126-DE9F73C7AA89}.Debug|x86.ActiveCfg = Debug|Any CPU
43 | {61F9CED4-DF01-40F5-A126-DE9F73C7AA89}.Debug|x86.Build.0 = Debug|Any CPU
44 | {61F9CED4-DF01-40F5-A126-DE9F73C7AA89}.Release|Any CPU.ActiveCfg = Release|Any CPU
45 | {61F9CED4-DF01-40F5-A126-DE9F73C7AA89}.Release|Any CPU.Build.0 = Release|Any CPU
46 | {61F9CED4-DF01-40F5-A126-DE9F73C7AA89}.Release|x64.ActiveCfg = Release|Any CPU
47 | {61F9CED4-DF01-40F5-A126-DE9F73C7AA89}.Release|x64.Build.0 = Release|Any CPU
48 | {61F9CED4-DF01-40F5-A126-DE9F73C7AA89}.Release|x86.ActiveCfg = Release|Any CPU
49 | {61F9CED4-DF01-40F5-A126-DE9F73C7AA89}.Release|x86.Build.0 = Release|Any CPU
50 | {CE1B1BF2-9EF2-4C07-902F-817D81EFD22E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
51 | {CE1B1BF2-9EF2-4C07-902F-817D81EFD22E}.Debug|Any CPU.Build.0 = Debug|Any CPU
52 | {CE1B1BF2-9EF2-4C07-902F-817D81EFD22E}.Debug|x64.ActiveCfg = Debug|Any CPU
53 | {CE1B1BF2-9EF2-4C07-902F-817D81EFD22E}.Debug|x64.Build.0 = Debug|Any CPU
54 | {CE1B1BF2-9EF2-4C07-902F-817D81EFD22E}.Debug|x86.ActiveCfg = Debug|Any CPU
55 | {CE1B1BF2-9EF2-4C07-902F-817D81EFD22E}.Debug|x86.Build.0 = Debug|Any CPU
56 | {CE1B1BF2-9EF2-4C07-902F-817D81EFD22E}.Release|Any CPU.ActiveCfg = Release|Any CPU
57 | {CE1B1BF2-9EF2-4C07-902F-817D81EFD22E}.Release|Any CPU.Build.0 = Release|Any CPU
58 | {CE1B1BF2-9EF2-4C07-902F-817D81EFD22E}.Release|x64.ActiveCfg = Release|Any CPU
59 | {CE1B1BF2-9EF2-4C07-902F-817D81EFD22E}.Release|x64.Build.0 = Release|Any CPU
60 | {CE1B1BF2-9EF2-4C07-902F-817D81EFD22E}.Release|x86.ActiveCfg = Release|Any CPU
61 | {CE1B1BF2-9EF2-4C07-902F-817D81EFD22E}.Release|x86.Build.0 = Release|Any CPU
62 | {B1139AC3-3DC2-453D-9A72-9C7196F9759C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
63 | {B1139AC3-3DC2-453D-9A72-9C7196F9759C}.Debug|Any CPU.Build.0 = Debug|Any CPU
64 | {B1139AC3-3DC2-453D-9A72-9C7196F9759C}.Debug|x64.ActiveCfg = Debug|Any CPU
65 | {B1139AC3-3DC2-453D-9A72-9C7196F9759C}.Debug|x64.Build.0 = Debug|Any CPU
66 | {B1139AC3-3DC2-453D-9A72-9C7196F9759C}.Debug|x86.ActiveCfg = Debug|Any CPU
67 | {B1139AC3-3DC2-453D-9A72-9C7196F9759C}.Debug|x86.Build.0 = Debug|Any CPU
68 | {B1139AC3-3DC2-453D-9A72-9C7196F9759C}.Release|Any CPU.ActiveCfg = Release|Any CPU
69 | {B1139AC3-3DC2-453D-9A72-9C7196F9759C}.Release|Any CPU.Build.0 = Release|Any CPU
70 | {B1139AC3-3DC2-453D-9A72-9C7196F9759C}.Release|x64.ActiveCfg = Release|Any CPU
71 | {B1139AC3-3DC2-453D-9A72-9C7196F9759C}.Release|x64.Build.0 = Release|Any CPU
72 | {B1139AC3-3DC2-453D-9A72-9C7196F9759C}.Release|x86.ActiveCfg = Release|Any CPU
73 | {B1139AC3-3DC2-453D-9A72-9C7196F9759C}.Release|x86.Build.0 = Release|Any CPU
74 | {D6E4407A-586B-4D75-A5F7-5AC9E7016614}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
75 | {D6E4407A-586B-4D75-A5F7-5AC9E7016614}.Debug|Any CPU.Build.0 = Debug|Any CPU
76 | {D6E4407A-586B-4D75-A5F7-5AC9E7016614}.Debug|x64.ActiveCfg = Debug|Any CPU
77 | {D6E4407A-586B-4D75-A5F7-5AC9E7016614}.Debug|x64.Build.0 = Debug|Any CPU
78 | {D6E4407A-586B-4D75-A5F7-5AC9E7016614}.Debug|x86.ActiveCfg = Debug|Any CPU
79 | {D6E4407A-586B-4D75-A5F7-5AC9E7016614}.Debug|x86.Build.0 = Debug|Any CPU
80 | {D6E4407A-586B-4D75-A5F7-5AC9E7016614}.Release|Any CPU.ActiveCfg = Release|Any CPU
81 | {D6E4407A-586B-4D75-A5F7-5AC9E7016614}.Release|Any CPU.Build.0 = Release|Any CPU
82 | {D6E4407A-586B-4D75-A5F7-5AC9E7016614}.Release|x64.ActiveCfg = Release|Any CPU
83 | {D6E4407A-586B-4D75-A5F7-5AC9E7016614}.Release|x64.Build.0 = Release|Any CPU
84 | {D6E4407A-586B-4D75-A5F7-5AC9E7016614}.Release|x86.ActiveCfg = Release|Any CPU
85 | {D6E4407A-586B-4D75-A5F7-5AC9E7016614}.Release|x86.Build.0 = Release|Any CPU
86 | {3E0AA90A-F50F-4226-8236-947B6DC82BCC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
87 | {3E0AA90A-F50F-4226-8236-947B6DC82BCC}.Debug|Any CPU.Build.0 = Debug|Any CPU
88 | {3E0AA90A-F50F-4226-8236-947B6DC82BCC}.Debug|x64.ActiveCfg = Debug|Any CPU
89 | {3E0AA90A-F50F-4226-8236-947B6DC82BCC}.Debug|x64.Build.0 = Debug|Any CPU
90 | {3E0AA90A-F50F-4226-8236-947B6DC82BCC}.Debug|x86.ActiveCfg = Debug|Any CPU
91 | {3E0AA90A-F50F-4226-8236-947B6DC82BCC}.Debug|x86.Build.0 = Debug|Any CPU
92 | {3E0AA90A-F50F-4226-8236-947B6DC82BCC}.Release|Any CPU.ActiveCfg = Release|Any CPU
93 | {3E0AA90A-F50F-4226-8236-947B6DC82BCC}.Release|Any CPU.Build.0 = Release|Any CPU
94 | {3E0AA90A-F50F-4226-8236-947B6DC82BCC}.Release|x64.ActiveCfg = Release|Any CPU
95 | {3E0AA90A-F50F-4226-8236-947B6DC82BCC}.Release|x64.Build.0 = Release|Any CPU
96 | {3E0AA90A-F50F-4226-8236-947B6DC82BCC}.Release|x86.ActiveCfg = Release|Any CPU
97 | {3E0AA90A-F50F-4226-8236-947B6DC82BCC}.Release|x86.Build.0 = Release|Any CPU
98 | {94B60493-45E4-4437-9155-3D30DFBFB66A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
99 | {94B60493-45E4-4437-9155-3D30DFBFB66A}.Debug|Any CPU.Build.0 = Debug|Any CPU
100 | {94B60493-45E4-4437-9155-3D30DFBFB66A}.Debug|x64.ActiveCfg = Debug|Any CPU
101 | {94B60493-45E4-4437-9155-3D30DFBFB66A}.Debug|x64.Build.0 = Debug|Any CPU
102 | {94B60493-45E4-4437-9155-3D30DFBFB66A}.Debug|x86.ActiveCfg = Debug|Any CPU
103 | {94B60493-45E4-4437-9155-3D30DFBFB66A}.Debug|x86.Build.0 = Debug|Any CPU
104 | {94B60493-45E4-4437-9155-3D30DFBFB66A}.Release|Any CPU.ActiveCfg = Release|Any CPU
105 | {94B60493-45E4-4437-9155-3D30DFBFB66A}.Release|Any CPU.Build.0 = Release|Any CPU
106 | {94B60493-45E4-4437-9155-3D30DFBFB66A}.Release|x64.ActiveCfg = Release|Any CPU
107 | {94B60493-45E4-4437-9155-3D30DFBFB66A}.Release|x64.Build.0 = Release|Any CPU
108 | {94B60493-45E4-4437-9155-3D30DFBFB66A}.Release|x86.ActiveCfg = Release|Any CPU
109 | {94B60493-45E4-4437-9155-3D30DFBFB66A}.Release|x86.Build.0 = Release|Any CPU
110 | EndGlobalSection
111 | GlobalSection(SolutionProperties) = preSolution
112 | HideSolutionNode = FALSE
113 | EndGlobalSection
114 | GlobalSection(ExtensibilityGlobals) = postSolution
115 | SolutionGuid = {95F60BDF-4C1C-46AA-816D-E645235051C5}
116 | EndGlobalSection
117 | GlobalSection(NDepend) = preSolution
118 | Project = ".\BervProject.WebApi.Boilerplate.ndproj"
119 | EndGlobalSection
120 | EndGlobal
121 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/.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 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015/2017 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # Visual Studio 2017 auto generated files
33 | Generated\ Files/
34 |
35 | # MSTest test Results
36 | [Tt]est[Rr]esult*/
37 | [Bb]uild[Ll]og.*
38 |
39 | # NUNIT
40 | *.VisualState.xml
41 | TestResult.xml
42 |
43 | # Build Results of an ATL Project
44 | [Dd]ebugPS/
45 | [Rr]eleasePS/
46 | dlldata.c
47 |
48 | # Benchmark Results
49 | BenchmarkDotNet.Artifacts/
50 |
51 | # .NET Core
52 | project.lock.json
53 | project.fragment.lock.json
54 | artifacts/
55 | **/Properties/launchSettings.json
56 |
57 | # StyleCop
58 | StyleCopReport.xml
59 |
60 | # Files built by Visual Studio
61 | *_i.c
62 | *_p.c
63 | *_i.h
64 | *.ilk
65 | *.meta
66 | *.obj
67 | *.iobj
68 | *.pch
69 | *.pdb
70 | *.ipdb
71 | *.pgc
72 | *.pgd
73 | *.rsp
74 | *.sbr
75 | *.tlb
76 | *.tli
77 | *.tlh
78 | *.tmp
79 | *.tmp_proj
80 | *.log
81 | *.vspscc
82 | *.vssscc
83 | .builds
84 | *.pidb
85 | *.svclog
86 | *.scc
87 |
88 | # Chutzpah Test files
89 | _Chutzpah*
90 |
91 | # Visual C++ cache files
92 | ipch/
93 | *.aps
94 | *.ncb
95 | *.opendb
96 | *.opensdf
97 | *.sdf
98 | *.cachefile
99 | *.VC.db
100 | *.VC.VC.opendb
101 |
102 | # Visual Studio profiler
103 | *.psess
104 | *.vsp
105 | *.vspx
106 | *.sap
107 |
108 | # Visual Studio Trace Files
109 | *.e2e
110 |
111 | # TFS 2012 Local Workspace
112 | $tf/
113 |
114 | # Guidance Automation Toolkit
115 | *.gpState
116 |
117 | # ReSharper is a .NET coding add-in
118 | _ReSharper*/
119 | *.[Rr]e[Ss]harper
120 | *.DotSettings.user
121 |
122 | # JustCode is a .NET coding add-in
123 | .JustCode
124 |
125 | # TeamCity is a build add-in
126 | _TeamCity*
127 |
128 | # DotCover is a Code Coverage Tool
129 | *.dotCover
130 |
131 | # AxoCover is a Code Coverage Tool
132 | .axoCover/*
133 | !.axoCover/settings.json
134 |
135 | # Visual Studio code coverage results
136 | *.coverage
137 | *.coveragexml
138 |
139 | # NCrunch
140 | _NCrunch_*
141 | .*crunch*.local.xml
142 | nCrunchTemp_*
143 |
144 | # MightyMoose
145 | *.mm.*
146 | AutoTest.Net/
147 |
148 | # Web workbench (sass)
149 | .sass-cache/
150 |
151 | # Installshield output folder
152 | [Ee]xpress/
153 |
154 | # DocProject is a documentation generator add-in
155 | DocProject/buildhelp/
156 | DocProject/Help/*.HxT
157 | DocProject/Help/*.HxC
158 | DocProject/Help/*.hhc
159 | DocProject/Help/*.hhk
160 | DocProject/Help/*.hhp
161 | DocProject/Help/Html2
162 | DocProject/Help/html
163 |
164 | # Click-Once directory
165 | publish/
166 |
167 | # Publish Web Output
168 | *.[Pp]ublish.xml
169 | *.azurePubxml
170 | # Note: Comment the next line if you want to checkin your web deploy settings,
171 | # but database connection strings (with potential passwords) will be unencrypted
172 | *.pubxml
173 | *.publishproj
174 |
175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
176 | # checkin your Azure Web App publish settings, but sensitive information contained
177 | # in these scripts will be unencrypted
178 | PublishScripts/
179 |
180 | # NuGet Packages
181 | *.nupkg
182 | # The packages folder can be ignored because of Package Restore
183 | **/[Pp]ackages/*
184 | # except build/, which is used as an MSBuild target.
185 | !**/[Pp]ackages/build/
186 | # Uncomment if necessary however generally it will be regenerated when needed
187 | #!**/[Pp]ackages/repositories.config
188 | # NuGet v3's project.json files produces more ignorable files
189 | *.nuget.props
190 | *.nuget.targets
191 |
192 | # Microsoft Azure Build Output
193 | csx/
194 | *.build.csdef
195 |
196 | # Microsoft Azure Emulator
197 | ecf/
198 | rcf/
199 |
200 | # Windows Store app package directories and files
201 | AppPackages/
202 | BundleArtifacts/
203 | Package.StoreAssociation.xml
204 | _pkginfo.txt
205 | *.appx
206 |
207 | # Visual Studio cache files
208 | # files ending in .cache can be ignored
209 | *.[Cc]ache
210 | # but keep track of directories ending in .cache
211 | !*.[Cc]ache/
212 |
213 | # Others
214 | ClientBin/
215 | ~$*
216 | *~
217 | *.dbmdl
218 | *.dbproj.schemaview
219 | *.jfm
220 | *.pfx
221 | *.publishsettings
222 | orleans.codegen.cs
223 |
224 | # Including strong name files can present a security risk
225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
226 | #*.snk
227 |
228 | # Since there are multiple workflows, uncomment next line to ignore bower_components
229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
230 | #bower_components/
231 |
232 | # RIA/Silverlight projects
233 | Generated_Code/
234 |
235 | # Backup & report files from converting an old project file
236 | # to a newer Visual Studio version. Backup files are not needed,
237 | # because we have git ;-)
238 | _UpgradeReport_Files/
239 | Backup*/
240 | UpgradeLog*.XML
241 | UpgradeLog*.htm
242 | ServiceFabricBackup/
243 | *.rptproj.bak
244 |
245 | # SQL Server files
246 | *.mdf
247 | *.ldf
248 | *.ndf
249 |
250 | # Business Intelligence projects
251 | *.rdl.data
252 | *.bim.layout
253 | *.bim_*.settings
254 | *.rptproj.rsuser
255 |
256 | # Microsoft Fakes
257 | FakesAssemblies/
258 |
259 | # GhostDoc plugin setting file
260 | *.GhostDoc.xml
261 |
262 | # Node.js Tools for Visual Studio
263 | .ntvs_analysis.dat
264 | node_modules/
265 |
266 | # Visual Studio 6 build log
267 | *.plg
268 |
269 | # Visual Studio 6 workspace options file
270 | *.opt
271 |
272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
273 | *.vbw
274 |
275 | # Visual Studio LightSwitch build output
276 | **/*.HTMLClient/GeneratedArtifacts
277 | **/*.DesktopClient/GeneratedArtifacts
278 | **/*.DesktopClient/ModelManifest.xml
279 | **/*.Server/GeneratedArtifacts
280 | **/*.Server/ModelManifest.xml
281 | _Pvt_Extensions
282 |
283 | # Paket dependency manager
284 | .paket/paket.exe
285 | paket-files/
286 |
287 | # FAKE - F# Make
288 | .fake/
289 |
290 | # JetBrains Rider
291 | .idea/
292 | *.sln.iml
293 |
294 | # CodeRush
295 | .cr/
296 |
297 | # Python Tools for Visual Studio (PTVS)
298 | __pycache__/
299 | *.pyc
300 |
301 | # Cake - Uncomment if you are using it
302 | # tools/**
303 | # !tools/packages.config
304 |
305 | # Tabs Studio
306 | *.tss
307 |
308 | # Telerik's JustMock configuration file
309 | *.jmconfig
310 |
311 | # BizTalk build output
312 | *.btp.cs
313 | *.btm.cs
314 | *.odx.cs
315 | *.xsd.cs
316 |
317 | # OpenCover UI analysis results
318 | OpenCover/
319 |
320 | # Azure Stream Analytics local run output
321 | ASALocalRun/
322 |
323 | # MSBuild Binary and Structured Log
324 | *.binlog
325 |
326 | # NVidia Nsight GPU debugger configuration file
327 | *.nvuser
328 |
329 | # MFractors (Xamarin productivity tool) working folder
330 | .mfractor/
331 |
332 | logs/
333 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/BervProject.WebApi.Boilerplate.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | BervProject.WebApi.Boilerplate
6 | true
7 |
8 |
9 |
10 | bin\Debug\BervProject.WebApi.Boilerplate.xml
11 |
12 |
13 |
14 | bin\Release\BervProject.WebApi.Boilerplate.xml
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | all
38 | runtime; build; native; contentfiles; analyzers; buildtransitive
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/ConfigModel/AWSConfiguration.cs:
--------------------------------------------------------------------------------
1 | namespace BervProject.WebApi.Boilerplate.ConfigModel
2 | {
3 | public class AWSConfiguration
4 | {
5 | public AWSBasicConfiguration Basic { get; set; }
6 | public AWSEmailConfiguration Email { get; set; }
7 | public AWSDynamoConfiguration Dynamo { get; set; }
8 | }
9 |
10 | public class AWSAuth
11 | {
12 | public string AccessKey { get; set; }
13 | public string SecretKey { get; set; }
14 | }
15 |
16 | public class AWSBasicConfiguration
17 | {
18 | public AWSAuth Auth { get; set; }
19 | }
20 |
21 | public class AWSDynamoConfiguration
22 | {
23 | public string Location { get; set; }
24 | }
25 |
26 | public class AWSEmailConfiguration
27 | {
28 | public string Location { get; set; }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/ConfigModel/AzureConfiguration.cs:
--------------------------------------------------------------------------------
1 | namespace BervProject.WebApi.Boilerplate.ConfigModel
2 | {
3 | public class AzureConfiguration
4 | {
5 | public AzureServiceBus ServiceBus { get; set; }
6 | public AzureStorage Storage { get; set; }
7 | }
8 |
9 | public class AzureStorage
10 | {
11 | public StorageQueue Queue { get; set; }
12 | public BlobStorage Blob { get; set; }
13 | }
14 |
15 | public class BlobStorage
16 | {
17 | public string ContainerName { get; set; }
18 | }
19 |
20 | public class StorageQueue
21 | {
22 | public string QueueName { get; set; }
23 | }
24 |
25 | public class AzureServiceBus
26 | {
27 | public string QueueName { get; set; }
28 | public string TopicName { get; set; }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Controllers/AWSS3Controller.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading.Tasks;
3 | using BervProject.WebApi.Boilerplate.Services.AWS;
4 | using Microsoft.AspNetCore.Mvc;
5 | using Microsoft.AspNetCore.Http;
6 |
7 | namespace BervProject.WebApi.Boilerplate.Controllers
8 | {
9 | [ApiController]
10 | [Route("api/v{version:apiVersion}/[controller]")]
11 | [ApiVersion("1.0")]
12 | public class SThreeController : ControllerBase
13 | {
14 | private readonly IAWSS3Service _awsS3Service;
15 | public SThreeController(IAWSS3Service awsS3Service)
16 | {
17 | _awsS3Service = awsS3Service;
18 | }
19 |
20 | ///
21 | /// Upload to S3
22 | ///
23 | ///
24 | ///
25 | [HttpPost("upload")]
26 | [ProducesResponseType(typeof(Dictionary), StatusCodes.Status200OK)]
27 | public async Task Upload([FromForm] IFormFile file)
28 | {
29 | var result = await _awsS3Service.UploadFile(file);
30 | return Ok(new
31 | {
32 | path = result
33 | });
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Controllers/BlobController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Reflection.Metadata;
4 | using BervProject.WebApi.Boilerplate.Models.Request;
5 | using BervProject.WebApi.Boilerplate.Services.Azure;
6 | using Microsoft.AspNetCore.Http;
7 | using Microsoft.AspNetCore.Mvc;
8 | using Microsoft.Extensions.Logging;
9 |
10 | namespace BervProject.WebApi.Boilerplate.Controllers
11 | {
12 | [ApiController]
13 | [Route("api/v{version:apiVersion}/[controller]")]
14 | [ApiVersion("1.0")]
15 | public class BlobController : ControllerBase
16 | {
17 | private readonly IBlobService _blobService;
18 | private readonly ILogger _logger;
19 |
20 | ///
21 | /// Blob Controller Constructor
22 | ///
23 | ///
24 | ///
25 | public BlobController(IBlobService blobService, ILogger logger)
26 | {
27 | _blobService = blobService;
28 | _logger = logger;
29 | }
30 |
31 | ///
32 | /// Create Blob Container
33 | ///
34 | /// true/false
35 | [HttpPost("create")]
36 | [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
37 | public IActionResult CreateBlobContainer()
38 | {
39 | _blobService.CreateStorageContainer();
40 | return Ok(true);
41 | }
42 |
43 | ///
44 | /// Return list of blob
45 | ///
46 | ///
47 | [HttpGet("list")]
48 | [Produces("application/json")]
49 | [ProducesResponseType(typeof(List>), StatusCodes.Status200OK)]
50 | public IActionResult ListBlob()
51 | {
52 | var info = _blobService.GetBlobsInfo();
53 | return Ok(info);
54 | }
55 |
56 | ///
57 | /// Upload Blob
58 | ///
59 | ///
60 | ///
61 | [HttpPost("upload")]
62 | [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
63 | public IActionResult Upload([FromForm] UploadFile uploadFile)
64 | {
65 | _blobService.UploadFile(uploadFile.File);
66 | return Ok(true);
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Controllers/CronController.cs:
--------------------------------------------------------------------------------
1 | using BervProject.WebApi.Boilerplate.Services;
2 | using Hangfire;
3 | using Microsoft.AspNetCore.Mvc;
4 | using System;
5 | using Microsoft.AspNetCore.Http;
6 |
7 | namespace BervProject.WebApi.Boilerplate.Controllers
8 | {
9 | [ApiController]
10 | [Route("api/v{version:apiVersion}/[controller]")]
11 | [ApiVersion("1.0")]
12 | public class CronController : ControllerBase
13 | {
14 | ///
15 | /// Create Cron Once
16 | ///
17 | ///
18 | ///
19 | [HttpPost("CreateCronOnce")]
20 | [ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
21 |
22 | public IActionResult CreateCronOnce([FromServices] IBackgroundJobClient backgroundJobClient)
23 | {
24 | var jobId = backgroundJobClient.Enqueue((x) => x.HelloWorld());
25 | return Ok(jobId);
26 | }
27 |
28 | ///
29 | /// Create Cron Recurance
30 | ///
31 | ///
32 | ///
33 | [HttpPost("CreateRecurance")]
34 | [ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
35 | public IActionResult CreateRecurance([FromServices] IRecurringJobManager recurringJobManager)
36 | {
37 | var jobId = "HelloWorld";
38 | recurringJobManager.AddOrUpdate(jobId, (x) => x.HelloWorld(), Cron.Hourly);
39 | return Ok(jobId);
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Controllers/DynamoController.cs:
--------------------------------------------------------------------------------
1 | using BervProject.WebApi.Boilerplate.Services.AWS;
2 | using Microsoft.AspNetCore.Mvc;
3 | using System.Threading.Tasks;
4 |
5 | // For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
6 |
7 | namespace BervProject.WebApi.Boilerplate.Controllers
8 | {
9 | [ApiController]
10 | [Route("api/v{version:apiVersion}/[controller]")]
11 | [ApiVersion("1.0")]
12 | public class DynamoController : ControllerBase
13 | {
14 | private readonly IDynamoDbServices _dynamoService;
15 | public DynamoController(IDynamoDbServices dynamoService)
16 | {
17 | _dynamoService = dynamoService;
18 | }
19 |
20 | ///
21 | /// Create Dynamo DB Object
22 | ///
23 | ///
24 | [HttpPost]
25 | public async Task Create()
26 | {
27 | await _dynamoService.CreateObject();
28 | return Ok();
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Controllers/EmailController.cs:
--------------------------------------------------------------------------------
1 | using BervProject.WebApi.Boilerplate.Models;
2 | using BervProject.WebApi.Boilerplate.Services.AWS;
3 | using Microsoft.AspNetCore.Mvc;
4 | using System.Threading.Tasks;
5 |
6 | namespace BervProject.WebApi.Boilerplate.Controllers
7 | {
8 | [ApiController]
9 | [Route("api/v{version:apiVersion}/[controller]")]
10 | [ApiVersion("1.0")]
11 | public class EmailController : ControllerBase
12 | {
13 | private readonly IEmailService _emailService;
14 | public EmailController(IEmailService emailService)
15 | {
16 | _emailService = emailService;
17 | }
18 |
19 | ///
20 | /// Send Email
21 | ///
22 | ///
23 | ///
24 | [HttpPost("send")]
25 | public async Task SendEmail([FromBody] EmailSendRequest request)
26 | {
27 | await _emailService.SendEmail(request.To);
28 | return Ok(new
29 | {
30 | Status = 200
31 | });
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Controllers/ErrorController.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc;
2 |
3 | namespace BervProject.WebApi.Boilerplate.Controllers
4 | {
5 | [ApiController]
6 | [Route("api/v{version:apiVersion}/[controller]")]
7 | [ApiVersion("1.0")]
8 | public class ErrorController : ControllerBase
9 | {
10 | ///
11 | /// Error Controller
12 | ///
13 | ///
14 | [Route("error")]
15 | [HttpGet]
16 | public IActionResult Error() => Problem();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Controllers/NoteController.cs:
--------------------------------------------------------------------------------
1 | using BervProject.WebApi.Boilerplate.Entities;
2 | using BervProject.WebApi.Boilerplate.Services;
3 | using Microsoft.AspNetCore.Mvc;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Http;
6 |
7 | namespace BervProject.WebApi.Boilerplate.Controllers
8 | {
9 | [ApiController]
10 | [Route("api/v{version:apiVersion}/[controller]")]
11 | [ApiVersion("1.0")]
12 | public class NoteController : ControllerBase
13 | {
14 | private readonly IAzureTableStorageService _noteTable;
15 | public NoteController(IAzureTableStorageService noteTable)
16 | {
17 | _noteTable = noteTable;
18 | }
19 |
20 | ///
21 | /// Create Azure Table Storage
22 | ///
23 | ///
24 | [HttpPost("createTable")]
25 | [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
26 |
27 | public async Task CreateTable()
28 | {
29 | await _noteTable.CreateTableAsync();
30 | return Ok(true);
31 | }
32 |
33 | ///
34 | /// Upsert Note
35 | ///
36 | ///
37 | ///
38 | [HttpPost("upsert")]
39 | [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
40 | public async Task UpsertNote([FromBody] Note note)
41 | {
42 | await _noteTable.UpsertAsync(note);
43 | return Ok(true);
44 | }
45 |
46 | ///
47 | /// Get Note
48 | ///
49 | ///
50 | ///
51 | ///
52 | [HttpGet("get")]
53 | [ProducesResponseType(typeof(Note), StatusCodes.Status200OK)]
54 | public async Task Get([FromQuery] string partitionKey, [FromQuery] string rowKey)
55 | {
56 | var result = await _noteTable.GetAsync(partitionKey, rowKey);
57 | return Ok(result);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Controllers/ServiceBusSenderController.cs:
--------------------------------------------------------------------------------
1 | using BervProject.WebApi.Boilerplate.Models;
2 | using BervProject.WebApi.Boilerplate.Models.Response;
3 | using BervProject.WebApi.Boilerplate.Services.Azure;
4 | using Microsoft.AspNetCore.Mvc;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Http;
7 |
8 | namespace BervProject.WebApi.Boilerplate.Controllers
9 | {
10 | [Route("api/v{version:apiVersion}/[controller]")]
11 | [ApiController]
12 | [ApiVersion("1.0")]
13 | public class ServiceBusSenderController : ControllerBase
14 | {
15 |
16 | ///
17 | /// Send Service Bus Message
18 | ///
19 | ///
20 | ///
21 | ///
22 | [HttpPost("sendMessage")]
23 | [ProducesResponseType(typeof(MessageSenderResponse), StatusCodes.Status200OK)]
24 | public async Task> SendMessage([FromServices] IAzureQueueServices queueServices, [FromBody] MessageData messageData)
25 | {
26 | var response = new MessageSenderResponse()
27 | {
28 | YourMessage = messageData.Message
29 | };
30 | var result = await queueServices.SendMessage(messageData.Message);
31 | response.IsSuccess = result;
32 | return response;
33 | }
34 |
35 | ///
36 | /// Send Topic Message
37 | ///
38 | ///
39 | ///
40 | ///
41 | [HttpPost("sendTopic")]
42 | [ProducesResponseType(typeof(MessageSenderResponse), StatusCodes.Status200OK)]
43 | public async Task> SendTopic([FromServices] ITopicServices topicServices, [FromBody] MessageData messageData)
44 | {
45 | var response = new MessageSenderResponse()
46 | {
47 | YourMessage = messageData.Message
48 | };
49 | var result = await topicServices.SendTopic(messageData.Message);
50 | response.IsSuccess = result;
51 | return response;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Controllers/StorageQueueController.cs:
--------------------------------------------------------------------------------
1 | using BervProject.WebApi.Boilerplate.Models;
2 | using BervProject.WebApi.Boilerplate.Models.Response;
3 | using BervProject.WebApi.Boilerplate.Services.Azure;
4 | using Microsoft.AspNetCore.Http;
5 | using Microsoft.AspNetCore.Mvc;
6 |
7 | namespace BervProject.WebApi.Boilerplate.Controllers
8 | {
9 | [ApiController]
10 | [Route("api/v{version:apiVersion}/[controller]")]
11 | [ApiVersion("1.0")]
12 | public class StorageQueueController : ControllerBase
13 | {
14 | private readonly IAzureStorageQueueService _azureStorageQueueService;
15 | public StorageQueueController(IAzureStorageQueueService azureStorageQueueService)
16 | {
17 | _azureStorageQueueService = azureStorageQueueService;
18 | }
19 |
20 | ///
21 | /// Send Queue Message
22 | ///
23 | ///
24 | ///
25 | [HttpPost("sendMessage")]
26 | [ProducesResponseType(typeof(MessageSenderResponse), StatusCodes.Status200OK)]
27 | public ActionResult SendMessage([FromBody] MessageData messageData)
28 | {
29 | var response = new MessageSenderResponse()
30 | {
31 | YourMessage = messageData.Message
32 | };
33 | var result = _azureStorageQueueService.SendMessage(messageData.Message);
34 | response.IsSuccess = result;
35 | return response;
36 | }
37 |
38 | ///
39 | /// Getting Latest Message
40 | ///
41 | ///
42 | [HttpGet("receiveMessage")]
43 | [ProducesResponseType(typeof(MessageSenderResponse), StatusCodes.Status200OK)]
44 | public ActionResult GetLatestMessage()
45 | {
46 | var response = new MessageSenderResponse();
47 | var result = _azureStorageQueueService.ReceiveMessage();
48 | response.IsSuccess = result != null;
49 | response.YourMessage = result;
50 | return response;
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Controllers/WeatherForecastController.cs:
--------------------------------------------------------------------------------
1 | using BervProject.WebApi.Boilerplate.Entities;
2 | using BervProject.WebApi.Boilerplate.EntityFramework;
3 | using BervProject.WebApi.Boilerplate.Models;
4 | using Microsoft.ApplicationInsights;
5 | using Microsoft.AspNetCore.Mvc;
6 | using Microsoft.EntityFrameworkCore;
7 | using Microsoft.Extensions.Caching.Distributed;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Linq;
11 | using System.Text;
12 | using Microsoft.AspNetCore.Http;
13 |
14 | namespace BervProject.WebApi.Boilerplate.Controllers
15 | {
16 | [ApiController]
17 | [Route("api/v{version:apiVersion}/[controller]")]
18 | [ApiVersion("1.0")]
19 | public class WeatherForecastController : ControllerBase
20 | {
21 | private static readonly string[] Summaries = new[]
22 | {
23 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
24 | };
25 |
26 | private readonly TelemetryClient telemetryClient;
27 |
28 | public WeatherForecastController(TelemetryClient telemetryClient)
29 | {
30 | this.telemetryClient = telemetryClient;
31 | }
32 |
33 | ///
34 | /// Get Weather Forecast
35 | ///
36 | ///
37 | [HttpGet]
38 | [ProducesResponseType(typeof(List), StatusCodes.Status200OK)]
39 | public IEnumerable Get()
40 | {
41 | this.telemetryClient.TrackEvent("WeatherQueried");
42 | var rng = new Random();
43 | return Enumerable.Range(1, 5).Select(index => new WeatherForecast
44 | {
45 | Date = DateTime.Now.AddDays(index),
46 | TemperatureC = rng.Next(-20, 55),
47 | Summary = Summaries[rng.Next(Summaries.Length)]
48 | })
49 | .ToArray();
50 | }
51 |
52 | ///
53 | /// Get Cache
54 | ///
55 | ///
56 | ///
57 | [HttpGet("cache")]
58 | [ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
59 | public ActionResult GetCache([FromServices] IDistributedCache distributedCache)
60 | {
61 | var result = distributedCache.Get("MyCache");
62 | if (result == null || result.Length == 0)
63 | {
64 | var utf8 = new UTF8Encoding();
65 | distributedCache.Set("MyCache", utf8.GetBytes("CustomCache"));
66 | result = distributedCache.Get("MyCache");
67 | Console.WriteLine(result);
68 | }
69 | return Encoding.UTF8.GetString(result ?? Array.Empty());
70 | }
71 |
72 | ///
73 | /// Simple DB Query
74 | ///
75 | ///
76 | ///
77 | [HttpGet("db")]
78 | [ProducesResponseType(typeof(List), StatusCodes.Status200OK)]
79 | public ActionResult> GetDb([FromServices] BoilerplateDbContext dbContext)
80 | {
81 | var booksQuery = dbContext.Books.AsQueryable();
82 | var books = booksQuery.Where(x => x.Name.Contains("Halleluya")).Include(x => x.Publisher).ToList();
83 | if (books.Count == 0)
84 | {
85 | var listBooks = new List()
86 | {
87 | new()
88 | {
89 | Id = Guid.NewGuid(),
90 | Name = "Halleluya",
91 | Publisher = new Publisher()
92 | {
93 | Id = Guid.NewGuid(),
94 | Name = "Heaven Publisher"
95 | }
96 | },
97 | new()
98 | {
99 | Id = Guid.NewGuid(),
100 | Name = "Halleluya 2",
101 | Publisher = new Publisher()
102 | {
103 | Id = Guid.NewGuid(),
104 | Name = "Heaven Publisher"
105 | }
106 | }
107 | };
108 | dbContext.Books.AddRange(listBooks);
109 | dbContext.SaveChanges();
110 | return Ok(listBooks);
111 | }
112 |
113 | return Ok(books);
114 | }
115 |
116 | ///
117 | /// Exception always throw
118 | ///
119 | ///
120 | ///
121 | [HttpGet("triggerException")]
122 | [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)]
123 | public IActionResult TriggerException()
124 | {
125 | throw new Exception("Unhandled Exception");
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Entities/Book.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel.DataAnnotations;
3 |
4 | namespace BervProject.WebApi.Boilerplate.Entities
5 | {
6 | public class Book
7 | {
8 | public Guid Id { get; set; }
9 | [Required]
10 | public string Name { get; set; }
11 | public virtual Publisher Publisher { get; set; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Entities/Note.cs:
--------------------------------------------------------------------------------
1 |
2 | using System;
3 | using Azure;
4 | using Azure.Data.Tables;
5 |
6 | namespace BervProject.WebApi.Boilerplate.Entities
7 | {
8 | public class Note : ITableEntity
9 | {
10 | public string PartitionKey { get; set; }
11 | public string RowKey { get; set; }
12 | public string Title { get; set; }
13 | public string Message { get; set; }
14 | public DateTimeOffset? Timestamp { get; set; }
15 | public ETag ETag { get; set; }
16 | }
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Entities/Publisher.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Text.Json.Serialization;
5 |
6 | namespace BervProject.WebApi.Boilerplate.Entities
7 | {
8 | public class Publisher
9 | {
10 | public Guid Id { get; set; }
11 | [Required]
12 | public string Name { get; set; }
13 | [JsonIgnore]
14 | public virtual ICollection Books { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/EntityFramework/BoilerplateDbContext.cs:
--------------------------------------------------------------------------------
1 | using BervProject.WebApi.Boilerplate.Entities;
2 | using Microsoft.EntityFrameworkCore;
3 |
4 | namespace BervProject.WebApi.Boilerplate.EntityFramework
5 | {
6 | public class BoilerplateDbContext : DbContext
7 | {
8 | public DbSet Books { get; set; }
9 | public DbSet Publishers { get; set; }
10 |
11 | public BoilerplateDbContext() : base()
12 | {
13 |
14 | }
15 |
16 | public BoilerplateDbContext(DbContextOptions options) : base(options)
17 | {
18 |
19 | }
20 |
21 | protected override void OnModelCreating(ModelBuilder modelBuilder)
22 | {
23 | base.OnModelCreating(modelBuilder);
24 | modelBuilder.Entity().HasOne(m => m.Publisher).WithMany(m => m.Books);
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Extensions/SetupAWSExtension.cs:
--------------------------------------------------------------------------------
1 | namespace BervProject.WebApi.Boilerplate.Extenstions;
2 | using Amazon.DynamoDBv2;
3 | using Amazon.S3;
4 | using Amazon.SimpleEmail;
5 | using BervProject.WebApi.Boilerplate.Services.AWS;
6 | using Microsoft.Extensions.DependencyInjection;
7 |
8 | public static class SetupAWSExtension
9 | {
10 | public static void SetupAWS(this IServiceCollection services)
11 | {
12 | services.AddAWSService();
13 | services.AddAWSService();
14 | services.AddAWSService();
15 | services.AddScoped();
16 | services.AddScoped();
17 | services.AddScoped();
18 | }
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Extensions/SetupAzureExtension.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Configuration;
2 |
3 | namespace BervProject.WebApi.Boilerplate.Extenstions;
4 |
5 | using Entities;
6 | using BervProject.WebApi.Boilerplate.Services.Azure;
7 | using Services;
8 | using Microsoft.Extensions.DependencyInjection;
9 | using Microsoft.Extensions.Azure;
10 |
11 |
12 | public static class SetupAzureExtension
13 | {
14 | public static void SetupAzure(this IServiceCollection services, ConfigurationManager config)
15 | {
16 | services.AddAzureClients(builder =>
17 | {
18 | builder.AddBlobServiceClient(config.GetConnectionString("AzureStorageBlob"));
19 | builder.AddQueueServiceClient(config.GetConnectionString("AzureStorageQueue"));
20 | builder.AddServiceBusClient(config.GetConnectionString("AzureServiceBus"));
21 | builder.AddTableServiceClient(config.GetConnectionString("AzureStorageTable"));
22 | });
23 | services.AddScoped();
24 | services.AddScoped();
25 | services.AddScoped();
26 | services.AddScoped();
27 | // add each tables
28 | services.AddScoped, AzureTableStorageService>();
29 | // service bus
30 | services.AddSingleton();
31 | services.AddSingleton();
32 | services.AddTransient();
33 | services.AddApplicationInsightsTelemetry();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Migrations/20210118042709_NewBookDb.Designer.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System;
3 | using BervProject.WebApi.Boilerplate.EntityFramework;
4 | using Microsoft.EntityFrameworkCore;
5 | using Microsoft.EntityFrameworkCore.Infrastructure;
6 | using Microsoft.EntityFrameworkCore.Migrations;
7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
8 | using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
9 |
10 | namespace BervProject.WebApi.Boilerplate.Migrations
11 | {
12 | [DbContext(typeof(BoilerplateDbContext))]
13 | [Migration("20210118042709_NewBookDb")]
14 | partial class NewBookDb
15 | {
16 | protected override void BuildTargetModel(ModelBuilder modelBuilder)
17 | {
18 | #pragma warning disable 612, 618
19 | modelBuilder
20 | .UseIdentityByDefaultColumns()
21 | .HasAnnotation("Relational:MaxIdentifierLength", 63)
22 | .HasAnnotation("ProductVersion", "5.0.2");
23 |
24 | modelBuilder.Entity("BervProject.WebApi.Boilerplate.Entities.Book", b =>
25 | {
26 | b.Property("Id")
27 | .ValueGeneratedOnAdd()
28 | .HasColumnType("uuid");
29 |
30 | b.Property("Name")
31 | .IsRequired()
32 | .HasColumnType("text");
33 |
34 | b.Property("PublisherId")
35 | .HasColumnType("uuid");
36 |
37 | b.HasKey("Id");
38 |
39 | b.HasIndex("PublisherId");
40 |
41 | b.ToTable("Books");
42 | });
43 |
44 | modelBuilder.Entity("BervProject.WebApi.Boilerplate.Entities.Publisher", b =>
45 | {
46 | b.Property("Id")
47 | .ValueGeneratedOnAdd()
48 | .HasColumnType("uuid");
49 |
50 | b.Property("Name")
51 | .IsRequired()
52 | .HasColumnType("text");
53 |
54 | b.HasKey("Id");
55 |
56 | b.ToTable("Publishers");
57 | });
58 |
59 | modelBuilder.Entity("BervProject.WebApi.Boilerplate.Entities.Book", b =>
60 | {
61 | b.HasOne("BervProject.WebApi.Boilerplate.Entities.Publisher", "Publisher")
62 | .WithMany("Books")
63 | .HasForeignKey("PublisherId");
64 |
65 | b.Navigation("Publisher");
66 | });
67 |
68 | modelBuilder.Entity("BervProject.WebApi.Boilerplate.Entities.Publisher", b =>
69 | {
70 | b.Navigation("Books");
71 | });
72 | #pragma warning restore 612, 618
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Migrations/20210118042709_NewBookDb.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore.Migrations;
2 | using System;
3 |
4 | namespace BervProject.WebApi.Boilerplate.Migrations
5 | {
6 | public partial class NewBookDb : Migration
7 | {
8 | protected override void Up(MigrationBuilder migrationBuilder)
9 | {
10 | migrationBuilder.CreateTable(
11 | name: "Publishers",
12 | columns: table => new
13 | {
14 | Id = table.Column(type: "uuid", nullable: false),
15 | Name = table.Column(type: "text", nullable: false)
16 | },
17 | constraints: table =>
18 | {
19 | table.PrimaryKey("PK_Publishers", x => x.Id);
20 | });
21 |
22 | migrationBuilder.CreateTable(
23 | name: "Books",
24 | columns: table => new
25 | {
26 | Id = table.Column(type: "uuid", nullable: false),
27 | Name = table.Column(type: "text", nullable: false),
28 | PublisherId = table.Column(type: "uuid", nullable: true)
29 | },
30 | constraints: table =>
31 | {
32 | table.PrimaryKey("PK_Books", x => x.Id);
33 | table.ForeignKey(
34 | name: "FK_Books_Publishers_PublisherId",
35 | column: x => x.PublisherId,
36 | principalTable: "Publishers",
37 | principalColumn: "Id",
38 | onDelete: ReferentialAction.Restrict);
39 | });
40 |
41 | migrationBuilder.CreateIndex(
42 | name: "IX_Books_PublisherId",
43 | table: "Books",
44 | column: "PublisherId");
45 | }
46 |
47 | protected override void Down(MigrationBuilder migrationBuilder)
48 | {
49 | migrationBuilder.DropTable(
50 | name: "Books");
51 |
52 | migrationBuilder.DropTable(
53 | name: "Publishers");
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Migrations/BoilerplateDbContextModelSnapshot.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System;
3 | using BervProject.WebApi.Boilerplate.EntityFramework;
4 | using Microsoft.EntityFrameworkCore;
5 | using Microsoft.EntityFrameworkCore.Infrastructure;
6 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
7 | using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
8 |
9 | namespace BervProject.WebApi.Boilerplate.Migrations
10 | {
11 | [DbContext(typeof(BoilerplateDbContext))]
12 | partial class BoilerplateDbContextModelSnapshot : ModelSnapshot
13 | {
14 | protected override void BuildModel(ModelBuilder modelBuilder)
15 | {
16 | #pragma warning disable 612, 618
17 | modelBuilder
18 | .UseIdentityByDefaultColumns()
19 | .HasAnnotation("Relational:MaxIdentifierLength", 63)
20 | .HasAnnotation("ProductVersion", "5.0.2");
21 |
22 | modelBuilder.Entity("BervProject.WebApi.Boilerplate.Entities.Book", b =>
23 | {
24 | b.Property("Id")
25 | .ValueGeneratedOnAdd()
26 | .HasColumnType("uuid");
27 |
28 | b.Property("Name")
29 | .IsRequired()
30 | .HasColumnType("text");
31 |
32 | b.Property("PublisherId")
33 | .HasColumnType("uuid");
34 |
35 | b.HasKey("Id");
36 |
37 | b.HasIndex("PublisherId");
38 |
39 | b.ToTable("Books");
40 | });
41 |
42 | modelBuilder.Entity("BervProject.WebApi.Boilerplate.Entities.Publisher", b =>
43 | {
44 | b.Property("Id")
45 | .ValueGeneratedOnAdd()
46 | .HasColumnType("uuid");
47 |
48 | b.Property("Name")
49 | .IsRequired()
50 | .HasColumnType("text");
51 |
52 | b.HasKey("Id");
53 |
54 | b.ToTable("Publishers");
55 | });
56 |
57 | modelBuilder.Entity("BervProject.WebApi.Boilerplate.Entities.Book", b =>
58 | {
59 | b.HasOne("BervProject.WebApi.Boilerplate.Entities.Publisher", "Publisher")
60 | .WithMany("Books")
61 | .HasForeignKey("PublisherId");
62 |
63 | b.Navigation("Publisher");
64 | });
65 |
66 | modelBuilder.Entity("BervProject.WebApi.Boilerplate.Entities.Publisher", b =>
67 | {
68 | b.Navigation("Books");
69 | });
70 | #pragma warning restore 612, 618
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Models/EmailSendRequest.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.ComponentModel.DataAnnotations;
3 |
4 | namespace BervProject.WebApi.Boilerplate.Models
5 | {
6 | public class EmailSendRequest
7 | {
8 | [Required]
9 | public List To { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Models/MessageData.cs:
--------------------------------------------------------------------------------
1 | namespace BervProject.WebApi.Boilerplate.Models
2 | {
3 | public class MessageData
4 | {
5 | public string Message { get; set; }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Models/Request/UploadFile.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Http;
2 | using Newtonsoft.Json;
3 | using System.ComponentModel.DataAnnotations;
4 |
5 | namespace BervProject.WebApi.Boilerplate.Models.Request
6 | {
7 | public class UploadFile
8 | {
9 | [Required]
10 | public IFormFile File { get; set; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Models/Response/MessageSenderResponse.cs:
--------------------------------------------------------------------------------
1 | namespace BervProject.WebApi.Boilerplate.Models.Response
2 | {
3 | public class MessageSenderResponse
4 | {
5 | public bool IsSuccess { get; set; }
6 | public string YourMessage { get; set; }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Models/WeatherForecast.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace BervProject.WebApi.Boilerplate.Models
4 | {
5 | public class WeatherForecast
6 | {
7 | public DateTime Date { get; set; }
8 |
9 | public int TemperatureC { get; set; }
10 |
11 | public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
12 |
13 | public string Summary { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/NLog.config:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Reflection;
4 | using Autofac.Extensions.DependencyInjection;
5 | using BervProject.WebApi.Boilerplate.ConfigModel;
6 | using BervProject.WebApi.Boilerplate.EntityFramework;
7 | using BervProject.WebApi.Boilerplate.Extenstions;
8 | using BervProject.WebApi.Boilerplate.Services;
9 | using BervProject.WebApi.Boilerplate.Services.Azure;
10 | using Hangfire;
11 | using Hangfire.PostgreSql;
12 | using Microsoft.AspNetCore.Builder;
13 | using Microsoft.EntityFrameworkCore;
14 | using Microsoft.Extensions.Configuration;
15 | using Microsoft.Extensions.DependencyInjection;
16 | using Microsoft.Extensions.Hosting;
17 | using Microsoft.Extensions.Logging;
18 | using Microsoft.OpenApi.Models;
19 | using NLog.Web;
20 |
21 | var builder = WebApplication.CreateBuilder(args);
22 | builder.AddServiceDefaults();
23 | builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
24 | builder.Logging.ClearProviders();
25 | builder.Logging.SetMinimumLevel(LogLevel.Trace);
26 | builder.Logging.AddNLog("Nlog.config");
27 | builder.Logging.AddNLogWeb();
28 | builder.Host.UseNLog();
29 |
30 | // settings injection
31 | var awsConfig = builder.Configuration.GetSection("AWS").Get();
32 | builder.Services.AddSingleton(awsConfig);
33 |
34 | var azureConfig = builder.Configuration.GetSection("Azure").Get();
35 | builder.Services.AddSingleton(azureConfig);
36 |
37 | // aws services
38 | builder.Services.SetupAWS();
39 |
40 | // azure services
41 | builder.Services.SetupAzure(builder.Configuration);
42 |
43 | // cron services
44 | builder.Services.AddScoped();
45 | builder.Services.AddHangfire(x => x.UsePostgreSqlStorage(opt =>
46 | {
47 | opt.UseNpgsqlConnection(builder.Configuration.GetConnectionString("BoilerplateConnectionString"));
48 | }));
49 | builder.Services.AddHangfireServer();
50 |
51 | // essential services
52 | builder.Services.AddStackExchangeRedisCache(options =>
53 | {
54 | options.Configuration = builder.Configuration.GetConnectionString("Redis");
55 | });
56 | builder.Services.AddDbContext(options => options.UseNpgsql(builder.Configuration.GetConnectionString("BoilerplateConnectionString")));
57 |
58 | builder.Services.AddControllers();
59 | builder.Services.AddApiVersioning();
60 | builder.Services.AddSwaggerGen(options =>
61 | {
62 | var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
63 | options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
64 | options.SwaggerDoc("v1", new OpenApiInfo
65 | {
66 | Version = "v1",
67 | Title = "Boilerplate API",
68 | Description = "An ASP.NET Core Web API"
69 | });
70 | });
71 |
72 | var app = builder.Build();
73 |
74 | // register Consumer
75 | var connectionString = builder.Configuration.GetConnectionString("AzureServiceBus");
76 | var queueName = azureConfig.ServiceBus.QueueName;
77 | var topicName = azureConfig.ServiceBus.TopicName;
78 | if (!string.IsNullOrWhiteSpace(queueName) && !string.IsNullOrWhiteSpace(connectionString))
79 | {
80 | var bus = app.Services.GetService();
81 | bus.RegisterOnMessageHandlerAndReceiveMessages();
82 | }
83 | if (!string.IsNullOrWhiteSpace(topicName) && !string.IsNullOrWhiteSpace(connectionString))
84 | {
85 | var bus = app.Services.GetService();
86 | bus.RegisterOnMessageHandlerAndReceiveMessages();
87 | }
88 |
89 | // register essential things
90 | if (app.Environment.IsDevelopment())
91 | {
92 | app.UseDeveloperExceptionPage();
93 | }
94 | else
95 | {
96 | app.UseExceptionHandler("/error");
97 | app.UseHttpsRedirection();
98 | }
99 |
100 | app.UseRouting();
101 |
102 | app.UseAuthorization();
103 |
104 | app.UseSwagger(c =>
105 | {
106 | c.RouteTemplate = "api/docs/{documentName}/swagger.json";
107 | });
108 |
109 | app.UseSwaggerUI(c =>
110 | {
111 | c.SwaggerEndpoint("/api/docs/v1/swagger.json", "My API V1");
112 | c.RoutePrefix = "api/docs";
113 | });
114 |
115 | app.MapDefaultEndpoints();
116 |
117 | app.MapControllers();
118 | app.MapHangfireDashboard();
119 |
120 | app.Run();
121 |
122 | public partial class Program { }
123 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Services/AWS/AWSS3Service.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Microsoft.AspNetCore.Http;
3 | using Amazon.S3;
4 | using Amazon.S3.Model;
5 |
6 | namespace BervProject.WebApi.Boilerplate.Services.AWS
7 | {
8 | public class AWSS3Service : IAWSS3Service
9 | {
10 | private readonly IAmazonS3 _s3Client;
11 | public AWSS3Service(IAmazonS3 amazonS3)
12 | {
13 | _s3Client = amazonS3;
14 | }
15 | public async Task UploadFile(IFormFile formFile)
16 | {
17 | var location = $"uploads/{formFile.FileName}";
18 | using var stream = formFile.OpenReadStream();
19 | var putRequest = new PutObjectRequest
20 | {
21 | Key = location,
22 | BucketName = "upload-test-berv",
23 | InputStream = stream,
24 | AutoCloseStream = true,
25 | ContentType = formFile.ContentType
26 | };
27 | await _s3Client.PutObjectAsync(putRequest);
28 | return location;
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Services/AWS/DynamoDbServices.cs:
--------------------------------------------------------------------------------
1 | using Amazon.DynamoDBv2;
2 | using Amazon.DynamoDBv2.Model;
3 | using Microsoft.Extensions.Logging;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Text.Json;
7 | using System.Threading.Tasks;
8 |
9 | namespace BervProject.WebApi.Boilerplate.Services.AWS
10 | {
11 | public class DynamoDbServices : IDynamoDbServices
12 | {
13 | private readonly IAmazonDynamoDB _dynamoClient;
14 | private readonly ILogger _logger;
15 | public DynamoDbServices(IAmazonDynamoDB amazonDynamoDb, ILogger logger)
16 | {
17 | _logger = logger;
18 | _dynamoClient = amazonDynamoDb;
19 | }
20 |
21 | public async Task CreateObject()
22 | {
23 | var request = new PutItemRequest()
24 | {
25 | TableName = "dev-test",
26 | Item = new Dictionary
27 | {
28 | { "Id", new AttributeValue
29 | {
30 | S = Guid.NewGuid().ToString()
31 | }},
32 | { "Name", new AttributeValue
33 | {
34 | S = "Hello World!"
35 | }}
36 | }
37 | };
38 | var response = await _dynamoClient.PutItemAsync(request);
39 | string message = $"Response: {response.HttpStatusCode}, {JsonSerializer.Serialize(response.Attributes)}";
40 | _logger.LogInformation(message);
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Services/AWS/EmailService.cs:
--------------------------------------------------------------------------------
1 | using Amazon.SimpleEmail;
2 | using Amazon.SimpleEmail.Model;
3 | using Microsoft.Extensions.Logging;
4 | using System.Collections.Generic;
5 | using System.Text.Json;
6 | using System.Text.Json.Serialization;
7 | using System.Threading.Tasks;
8 |
9 | namespace BervProject.WebApi.Boilerplate.Services.AWS
10 | {
11 | public class EmailService : IEmailService
12 | {
13 | private readonly IAmazonSimpleEmailService _emailClient;
14 | private readonly ILogger _logger;
15 | public EmailService(ILogger logger, IAmazonSimpleEmailService emailClient)
16 | {
17 | _logger = logger;
18 | _emailClient = emailClient;
19 | }
20 |
21 | public async Task SendEmail(List receiver)
22 | {
23 | var request = new SendEmailRequest()
24 | {
25 | ReplyToAddresses = new List { "bervianto.leo@gmail.com" },
26 | Message = new Message()
27 | {
28 | Body = new Body(new Content("Hello World!")),
29 | Subject = new Content("Stand by me")
30 | },
31 | Destination = new Destination(receiver),
32 | Source = "support@berviantoleo.my.id"
33 | };
34 | var response = await _emailClient.SendEmailAsync(request);
35 | string messageId = $"Message id: {response.MessageId}";
36 | _logger.LogDebug(messageId);
37 | if (response.HttpStatusCode == System.Net.HttpStatusCode.OK)
38 | {
39 | _logger.LogInformation("Finished Sent Email");
40 | }
41 | else
42 | {
43 | _logger.LogWarning("There is a problem when sending email");
44 | string message = $"Error: {response.MessageId}:{response.HttpStatusCode}:{JsonSerializer.Serialize(response.ResponseMetadata.Metadata)}";
45 | _logger.LogWarning(message);
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Services/AWS/IAWSS3Service.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Microsoft.AspNetCore.Http;
3 |
4 | namespace BervProject.WebApi.Boilerplate.Services.AWS
5 | {
6 | public interface IAWSS3Service
7 | {
8 | Task UploadFile(IFormFile formFile);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Services/AWS/IDynamoDbServices.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace BervProject.WebApi.Boilerplate.Services.AWS
4 | {
5 | public interface IDynamoDbServices
6 | {
7 | Task CreateObject();
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Services/AWS/IEmailService.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading.Tasks;
3 |
4 | namespace BervProject.WebApi.Boilerplate.Services.AWS
5 | {
6 | public interface IEmailService
7 | {
8 | Task SendEmail(List receiver);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Services/Azure/AzureQueueServices.cs:
--------------------------------------------------------------------------------
1 | using Azure.Messaging.ServiceBus;
2 | using BervProject.WebApi.Boilerplate.ConfigModel;
3 | using Microsoft.Extensions.Logging;
4 | using System;
5 | using System.Threading.Tasks;
6 |
7 | namespace BervProject.WebApi.Boilerplate.Services.Azure
8 | {
9 | public class AzureQueueServices : IAzureQueueServices
10 | {
11 | private readonly string _queueName;
12 | private readonly ServiceBusSender _serviceBusSender;
13 | private readonly ILogger _logger;
14 | public AzureQueueServices(AzureConfiguration azureConfiguration, ILogger logger, ServiceBusClient serviceBusClient)
15 | {
16 | _logger = logger;
17 | _queueName = azureConfiguration.ServiceBus.QueueName;
18 | _serviceBusSender = serviceBusClient.CreateSender(_queueName);
19 | }
20 |
21 | public async Task SendMessage(string message)
22 | {
23 | try
24 | {
25 | var messageQueue = new ServiceBusMessage(message);
26 | _logger.LogDebug($"Sending message: {message}");
27 | await _serviceBusSender.SendMessageAsync(messageQueue);
28 | _logger.LogDebug($"Sent message: {message}");
29 | return true;
30 | }
31 | catch (Exception ex)
32 | {
33 | _logger.LogError(ex.ToString());
34 | return false;
35 | }
36 | finally
37 | {
38 | await _serviceBusSender.CloseAsync();
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Services/Azure/AzureStorageQueueService.cs:
--------------------------------------------------------------------------------
1 | using Azure.Storage.Queues;
2 | using BervProject.WebApi.Boilerplate.ConfigModel;
3 | using Microsoft.Extensions.Logging;
4 | using System;
5 |
6 | namespace BervProject.WebApi.Boilerplate.Services.Azure
7 | {
8 | public class AzureStorageQueueService : IAzureStorageQueueService
9 | {
10 | private readonly ILogger _logger;
11 | private readonly QueueClient _queueClient;
12 | private readonly string _queueName;
13 |
14 | public AzureStorageQueueService(ILogger logger,
15 | AzureConfiguration azureConfiguration,
16 | QueueServiceClient queueServiceClient)
17 | {
18 | _logger = logger;
19 | _queueName = azureConfiguration.Storage.Queue.QueueName;
20 | _queueClient = queueServiceClient.GetQueueClient(_queueName);
21 | _queueClient.CreateIfNotExists();
22 | }
23 |
24 | public string ReceiveMessage()
25 | {
26 | try
27 | {
28 | if (_queueClient.Exists())
29 | {
30 | var response = _queueClient.ReceiveMessage();
31 | var message = response?.Value;
32 | if (message != null)
33 | {
34 | var textMessage = message.Body.ToString();
35 | _logger.LogDebug($"Get message from {_queueName}:{message.MessageId}: {textMessage}");
36 | _logger.LogDebug($"Message {message.MessageId} deqeue from {_queueName}");
37 | var responseDelete = _queueClient.DeleteMessage(message.MessageId, message.PopReceipt);
38 | _logger.LogDebug($"Message finished deqeue from {_queueName}: {responseDelete.ClientRequestId}");
39 | return textMessage;
40 | }
41 | else
42 | {
43 | _logger.LogDebug($"Empty message at {_queueName}");
44 | return null;
45 | }
46 | }
47 | else
48 | {
49 | _logger.LogWarning($"{_queueName} is not exists");
50 | return null;
51 | }
52 | }
53 | catch (Exception ex)
54 | {
55 | _logger.LogError(ex, "Something Error, ignoring");
56 | return null;
57 | }
58 | }
59 |
60 | public bool SendMessage(string message)
61 | {
62 | try
63 | {
64 | if (_queueClient.Exists())
65 | {
66 | _logger.LogDebug($"Sending message: {message} at {_queueName}");
67 | var response = _queueClient.SendMessage(message);
68 | var messageId = response?.Value?.MessageId;
69 | _logger.LogDebug($"Sent message to {_queueName} with id: {messageId}");
70 | return true;
71 | }
72 | else
73 | {
74 | _logger.LogWarning($"{_queueName} is not exists");
75 | return false;
76 | }
77 | }
78 | catch (Exception ex)
79 | {
80 | _logger.LogError(ex.ToString());
81 | return false;
82 | }
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Services/Azure/AzureTableStorageService.cs:
--------------------------------------------------------------------------------
1 |
2 | using Azure.Data.Tables;
3 | using BervProject.WebApi.Boilerplate.ConfigModel;
4 | using Microsoft.EntityFrameworkCore.Infrastructure;
5 | using Microsoft.Extensions.Logging;
6 | using System.Threading.Tasks;
7 |
8 | namespace BervProject.WebApi.Boilerplate.Services.Azure
9 | {
10 | public class AzureTableStorageService : IAzureTableStorageService
11 | where T : class, ITableEntity, new()
12 | {
13 | private readonly ILogger> _logger;
14 | private readonly TableServiceClient _tableServiceClient;
15 | private readonly string _tableName;
16 | public AzureTableStorageService(ILogger> logger,
17 | AzureConfiguration azureConfiguration,
18 | TableServiceClient tableServiceClient)
19 | {
20 | _logger = logger;
21 | _tableServiceClient = tableServiceClient;
22 | _tableName = typeof(T).ShortDisplayName();
23 | }
24 |
25 | public async Task CreateTableAsync()
26 | {
27 | _logger.LogInformation($"Creating table: {_tableName}");
28 | await _tableServiceClient.CreateTableIfNotExistsAsync(_tableName);
29 | _logger.LogInformation($"{_tableName} created");
30 | }
31 |
32 | public async Task UpsertAsync(T data)
33 | {
34 | var tableClient = _tableServiceClient.GetTableClient(_tableName);
35 | var response = await tableClient.UpsertEntityAsync(data);
36 | if (response.IsError)
37 | {
38 | _logger.LogError(response.ReasonPhrase);
39 | }
40 | }
41 |
42 | public async Task GetAsync(string partitionKey, string rowKey)
43 | {
44 | var tableClient = _tableServiceClient.GetTableClient(_tableName);
45 | var response = await tableClient.GetEntityAsync(partitionKey, rowKey);
46 | return response.Value;
47 | }
48 | }
49 | }
50 |
51 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Services/Azure/BlobService.cs:
--------------------------------------------------------------------------------
1 | using Azure.Storage.Blobs;
2 | using BervProject.WebApi.Boilerplate.ConfigModel;
3 | using Microsoft.AspNetCore.Http;
4 | using Microsoft.Extensions.Logging;
5 | using System.Collections.Generic;
6 |
7 | namespace BervProject.WebApi.Boilerplate.Services.Azure
8 | {
9 | public class BlobService : IBlobService
10 | {
11 | private readonly ILogger _logger;
12 | private readonly BlobContainerClient _blobContainerClient;
13 | private readonly string _containerName;
14 | public BlobService(ILogger logger, AzureConfiguration azureConfiguration, BlobServiceClient blobServiceClient)
15 | {
16 | _logger = logger;
17 | _containerName = azureConfiguration.Storage.Blob.ContainerName;
18 | _blobContainerClient = blobServiceClient.GetBlobContainerClient(_containerName);
19 | }
20 |
21 | public void CreateStorageContainer()
22 | {
23 | _logger.LogDebug($"Create Blob Container {_containerName}");
24 | _blobContainerClient.CreateIfNotExists();
25 | _logger.LogDebug($"Blob Container {_containerName} created");
26 | }
27 |
28 | public List> GetBlobsInfo()
29 | {
30 | var list = new List>();
31 | if (_blobContainerClient.Exists())
32 | {
33 | var blobs = _blobContainerClient.GetBlobs();
34 | foreach (var blob in blobs)
35 | {
36 | _logger.LogDebug($"{blob.Name} --> Created On: {blob.Properties.CreatedOn:YYYY-MM-dd HH:mm:ss} Size: {blob.Properties.ContentLength}");
37 | list.Add(new Dictionary
38 | {
39 | { "name", blob.Name },
40 | { "createdDate", blob.Properties.CreatedOn?.ToString() },
41 | { "size", blob.Properties.ContentLength?.ToString() },
42 | { "version", blob.VersionId },
43 | { "deleted", blob.Deleted.ToString() }
44 | });
45 | }
46 | }
47 | else
48 | {
49 | _logger.LogWarning($"Can't get data, container {_containerName} not created yet");
50 | }
51 | return list;
52 | }
53 |
54 | public void UploadFile(IFormFile formFile)
55 | {
56 | if (_blobContainerClient.Exists())
57 | {
58 | var fileName = formFile.FileName;
59 | BlobClient blobClient = _blobContainerClient.GetBlobClient(fileName);
60 | using var stream = formFile.OpenReadStream();
61 | _logger.LogDebug($"Uploading {fileName}");
62 | blobClient.Upload(stream, true);
63 | _logger.LogDebug($"{fileName} uploaded");
64 | }
65 | else
66 | {
67 | _logger.LogWarning($"Can't upload, container {_containerName} not created yet");
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Services/Azure/IAzureQueueServices.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace BervProject.WebApi.Boilerplate.Services.Azure
4 | {
5 | public interface IAzureQueueServices
6 | {
7 | Task SendMessage(string message);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Services/Azure/IAzureStorageQueueService.cs:
--------------------------------------------------------------------------------
1 | namespace BervProject.WebApi.Boilerplate.Services.Azure
2 | {
3 | public interface IAzureStorageQueueService
4 | {
5 | bool SendMessage(string message);
6 | string ReceiveMessage();
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Services/Azure/IAzureTableStorageService.cs:
--------------------------------------------------------------------------------
1 | namespace BervProject.WebApi.Boilerplate.Services;
2 |
3 | using System.Threading.Tasks;
4 |
5 | public interface IAzureTableStorageService
6 | {
7 | Task CreateTableAsync();
8 | Task UpsertAsync(T data);
9 | Task GetAsync(string partitionKey, string rowKey);
10 | }
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Services/Azure/IBlobService.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Http;
2 | using System.Collections.Generic;
3 |
4 | namespace BervProject.WebApi.Boilerplate.Services.Azure
5 | {
6 | public interface IBlobService
7 | {
8 | void CreateStorageContainer();
9 | List> GetBlobsInfo();
10 | void UploadFile(IFormFile formFile);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Services/Azure/IServiceBusQueueConsumer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace BervProject.WebApi.Boilerplate.Services.Azure
4 | {
5 | public interface IServiceBusQueueConsumer
6 | {
7 | void RegisterOnMessageHandlerAndReceiveMessages();
8 | Task CloseQueueAsync();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Services/Azure/IServiceBusTopicSubscription.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace BervProject.WebApi.Boilerplate.Services.Azure
4 | {
5 | public interface IServiceBusTopicSubscription
6 | {
7 | void RegisterOnMessageHandlerAndReceiveMessages();
8 | Task CloseSubscriptionClientAsync();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Services/Azure/ITopicServices.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace BervProject.WebApi.Boilerplate.Services.Azure
4 | {
5 | public interface ITopicServices
6 | {
7 | Task SendTopic(string message);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Services/Azure/ServiceBusQueueConsumer.cs:
--------------------------------------------------------------------------------
1 | using Azure.Messaging.ServiceBus;
2 | using BervProject.WebApi.Boilerplate.ConfigModel;
3 | using Microsoft.Extensions.Logging;
4 | using System.Threading.Tasks;
5 |
6 | namespace BervProject.WebApi.Boilerplate.Services.Azure
7 | {
8 | public class ServiceBusQueueConsumer : IServiceBusQueueConsumer
9 | {
10 | private readonly ILogger _logger;
11 | private readonly string _queueName;
12 | private readonly ServiceBusProcessor _serviceBusProcessor;
13 | private readonly IProcessData _processData;
14 | public ServiceBusQueueConsumer(ILogger logger,
15 | IProcessData processData,
16 | AzureConfiguration azureConfiguration,
17 | ServiceBusClient serviceBusClient)
18 | {
19 | _logger = logger;
20 | _processData = processData;
21 | _queueName = azureConfiguration.ServiceBus.QueueName;
22 | var options = new ServiceBusProcessorOptions
23 | {
24 | // By default or when AutoCompleteMessages is set to true, the processor will complete the message after executing the message handler
25 | // Set AutoCompleteMessages to false to [settle messages](https://docs.microsoft.com/en-us/azure/service-bus-messaging/message-transfers-locks-settlement#peeklock) on your own.
26 | // In both cases, if the message handler throws an exception without settling the message, the processor will abandon the message.
27 | AutoCompleteMessages = false,
28 |
29 | // I can also allow for multi-threading
30 | MaxConcurrentCalls = 2
31 | };
32 | _serviceBusProcessor = serviceBusClient.CreateProcessor(_queueName, options);
33 | }
34 |
35 | public void RegisterOnMessageHandlerAndReceiveMessages()
36 | {
37 | _logger.LogDebug($"Register queue for {_queueName}");
38 | _serviceBusProcessor.ProcessMessageAsync += MessageHandler;
39 | _serviceBusProcessor.ProcessErrorAsync += ErrorHandler;
40 | _logger.LogDebug($"Registered queue for {_queueName}");
41 | }
42 |
43 | private async Task MessageHandler(ProcessMessageEventArgs args)
44 | {
45 | var myPayload = args.Message.Body.ToString();
46 | _processData.Process(myPayload);
47 | await args.CompleteMessageAsync(args.Message);
48 | }
49 |
50 | private Task ErrorHandler(ProcessErrorEventArgs args)
51 | {
52 | _logger.LogError(args.Exception, "Message handler encountered an exception");
53 |
54 | _logger.LogDebug($"- Error Source: {args.ErrorSource}");
55 | _logger.LogDebug($"- Entity Path: {args.EntityPath}");
56 | _logger.LogDebug($"- Identifier: {args.Identifier}");
57 | _logger.LogDebug($"- FullyQualifiedNamespace: {args.FullyQualifiedNamespace}");
58 |
59 | return Task.CompletedTask;
60 | }
61 |
62 | public async Task CloseQueueAsync()
63 | {
64 | await _serviceBusProcessor.CloseAsync();
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Services/Azure/ServiceBusTopicSubscription.cs:
--------------------------------------------------------------------------------
1 | using Amazon.Runtime.Internal;
2 | using Azure.Messaging.ServiceBus;
3 | using BervProject.WebApi.Boilerplate.ConfigModel;
4 | using Microsoft.Azure.ServiceBus;
5 | using Microsoft.Extensions.Logging;
6 | using System.Diagnostics;
7 | using System.Text;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 |
11 | namespace BervProject.WebApi.Boilerplate.Services.Azure
12 | {
13 | public class ServiceBusTopicSubscription : IServiceBusTopicSubscription
14 | {
15 | private readonly ILogger _logger;
16 | private readonly string _topicName;
17 | private readonly string _topicSubscription = "topicSubscriptionRandom";
18 | private readonly ServiceBusProcessor _serviceBusProcessor;
19 | private readonly IProcessData _processData;
20 | public ServiceBusTopicSubscription(ILogger logger,
21 | IProcessData processData,
22 | AzureConfiguration azureConfiguration,
23 | ServiceBusClient serviceBusClient)
24 | {
25 | _logger = logger;
26 | _processData = processData;
27 | _topicName = azureConfiguration.ServiceBus.TopicName;
28 | var options = new ServiceBusProcessorOptions
29 | {
30 | // By default or when AutoCompleteMessages is set to true, the processor will complete the message after executing the message handler
31 | // Set AutoCompleteMessages to false to [settle messages](https://docs.microsoft.com/en-us/azure/service-bus-messaging/message-transfers-locks-settlement#peeklock) on your own.
32 | // In both cases, if the message handler throws an exception without settling the message, the processor will abandon the message.
33 | AutoCompleteMessages = false,
34 |
35 | // I can also allow for multi-threading
36 | MaxConcurrentCalls = 2
37 | };
38 | _serviceBusProcessor = serviceBusClient.CreateProcessor(_topicName, options);
39 | }
40 |
41 | public async Task CloseSubscriptionClientAsync()
42 | {
43 | await _serviceBusProcessor.CloseAsync();
44 | }
45 |
46 | public void RegisterOnMessageHandlerAndReceiveMessages()
47 | {
48 |
49 | _logger.LogDebug($"Register topic for {_topicName}/{_topicSubscription}");
50 | _serviceBusProcessor.ProcessMessageAsync += MessageHandler;
51 | _serviceBusProcessor.ProcessErrorAsync += ErrorHandler;
52 | _logger.LogDebug($"Registered topic for {_topicName}/{_topicSubscription}");
53 | }
54 |
55 | private async Task MessageHandler(ProcessMessageEventArgs args)
56 | {
57 | var myPayload = args.Message.Body.ToString();
58 | _processData.Process(myPayload);
59 | await args.CompleteMessageAsync(args.Message);
60 | }
61 |
62 | private Task ErrorHandler(ProcessErrorEventArgs args)
63 | {
64 | _logger.LogError(args.Exception, "Message handler encountered an exception");
65 |
66 | _logger.LogDebug($"- Error Source: {args.ErrorSource}");
67 | _logger.LogDebug($"- Entity Path: {args.EntityPath}");
68 | _logger.LogDebug($"- Identifier: {args.Identifier}");
69 | _logger.LogDebug($"- FullyQualifiedNamespace: {args.FullyQualifiedNamespace}");
70 |
71 | return Task.CompletedTask;
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Services/Azure/TopicServices.cs:
--------------------------------------------------------------------------------
1 | using Azure.Messaging.ServiceBus;
2 | using BervProject.WebApi.Boilerplate.ConfigModel;
3 | using Microsoft.Azure.ServiceBus;
4 | using Microsoft.Extensions.Logging;
5 | using System;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace BervProject.WebApi.Boilerplate.Services.Azure
10 | {
11 | public class TopicServices : ITopicServices
12 | {
13 | private readonly string _topicName;
14 | private readonly ServiceBusSender _serviceBusSender;
15 | private readonly ILogger _logger;
16 | public TopicServices(AzureConfiguration azureConfiguration, ILogger logger, ServiceBusClient serviceBusClient)
17 | {
18 | _logger = logger;
19 | _topicName = azureConfiguration.ServiceBus.TopicName;
20 | _serviceBusSender = serviceBusClient.CreateSender(_topicName);
21 | }
22 | public async Task SendTopic(string message)
23 | {
24 | try
25 | {
26 | var encodedMessage = new ServiceBusMessage(message);
27 | _logger.LogDebug($"Sending message: {message}");
28 | await _serviceBusSender.SendMessageAsync(encodedMessage);
29 | _logger.LogDebug($"Sent message: {message}");
30 | return true;
31 | }
32 | catch (Exception ex)
33 | {
34 | _logger.LogError(ex.ToString());
35 | return false;
36 | }
37 | finally
38 | {
39 | await _serviceBusSender.CloseAsync();
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Services/CronService.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 |
3 | namespace BervProject.WebApi.Boilerplate.Services
4 | {
5 | public class CronService : ICronService
6 | {
7 | private readonly ILogger _logger;
8 | public CronService(ILoggerFactory loggerFactory)
9 | {
10 | _logger = loggerFactory.CreateLogger();
11 | }
12 | public void HelloWorld()
13 | {
14 | _logger.LogDebug("Run Cron");
15 | _logger.LogInformation("Hello World Cron!");
16 | _logger.LogDebug("Finished Run Cron");
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Services/ICronService.cs:
--------------------------------------------------------------------------------
1 | namespace BervProject.WebApi.Boilerplate.Services
2 | {
3 | public interface ICronService
4 | {
5 | public void HelloWorld();
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Services/IProcessData.cs:
--------------------------------------------------------------------------------
1 | namespace BervProject.WebApi.Boilerplate.Services
2 | {
3 | public interface IProcessData
4 | {
5 | void Process(string message);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/Services/ProcessData.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 |
3 | namespace BervProject.WebApi.Boilerplate.Services
4 | {
5 | public class ProcessData : IProcessData
6 | {
7 | private readonly ILogger _logger;
8 | public ProcessData(ILogger logger)
9 | {
10 | _logger = logger;
11 | }
12 | public void Process(string message)
13 | {
14 | _logger.LogDebug($"You get message: {message}");
15 | // TODO: another handler
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Trace",
5 | "System": "Information",
6 | "Microsoft": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Boilerplate/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Trace",
5 | "Microsoft": "Information",
6 | "Microsoft.Hosting.Lifetime": "Information",
7 | "Hangfire": "Information"
8 | }
9 | },
10 | "AllowedHosts": "*",
11 | "AWS": {
12 | "Basic": {
13 | "Auth": {
14 | "AccessKey": "",
15 | "SecretKey": ""
16 | }
17 | },
18 | "Email": {
19 | "Location": "us-east-1"
20 | },
21 | "Dynamo": {
22 | "Location": "ap-southeast-1"
23 | }
24 | },
25 | "Azure": {
26 | "Storage": {
27 | "Blob": {
28 | "ContainerName": "testblob"
29 | },
30 | "Queue": {
31 | "QueueName": "testqueue"
32 | }
33 | },
34 | "ServiceBus": {
35 | "QueueName": "testqueue",
36 | "TopicName": "testtopic"
37 | }
38 | },
39 | "ConnectionStrings": {
40 | "BoilerplateConnectionString": "Host=localhost;Database=testdb;Username=postgres;Password=devpass4444",
41 | "AzureStorageBlob": "UseDevelopmentStorage=true",
42 | "AzureStorageQueue": "UseDevelopmentStorage=true",
43 | "AzureStorageTable": "UseDevelopmentStorage=true",
44 | "AzureServiceBus": "",
45 | "Redis": "localhost:6379"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Integration.Test/BervProject.WebApi.Integration.Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | enable
6 | enable
7 | false
8 | false
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | runtime; build; native; contentfiles; analyzers; buildtransitive
17 | all
18 |
19 |
20 | runtime; build; native; contentfiles; analyzers; buildtransitive
21 | all
22 |
23 |
24 |
25 |
26 |
27 |
28 | Always
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Integration.Test/BlobControllerTest.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Http.Json;
2 | using BervProject.WebApi.Integration.Test.Fixtures;
3 | using Microsoft.AspNetCore.Mvc.Testing;
4 | using Newtonsoft.Json.Linq;
5 |
6 | namespace BervProject.WebApi.Integration.Test
7 | {
8 | [Collection("Webapp")]
9 | public class BlobControllerTest
10 | {
11 | private readonly WebApplicationFactory _applicationFactory;
12 | public BlobControllerTest(WebAppFixture webAppFixtures)
13 | {
14 | this._applicationFactory = webAppFixtures.WebApp;
15 | }
16 | [Fact]
17 | public async Task UploadBlobTest()
18 | {
19 | var client = _applicationFactory.CreateClient();
20 | var response = await client.PostAsync("/api/v1.0/blob/create", null);
21 | Assert.True(response.IsSuccessStatusCode);
22 | using var file1 = File.OpenRead(@"Docs/test.txt");
23 | using var content1 = new StreamContent(file1);
24 | using var formData = new MultipartFormDataContent();
25 | formData.Add(content1, "file", "test.txt");
26 | response = await client.PostAsync("/api/v1.0/blob/upload", formData);
27 | Assert.True(response.IsSuccessStatusCode);
28 | response = await client.GetAsync("/api/v1.0/blob/list");
29 | Assert.True(response.IsSuccessStatusCode);
30 | var data = await response.Content.ReadFromJsonAsync>>();
31 | Assert.NotNull(data);
32 | Assert.Single(data);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Integration.Test/Collections/WebAppCollection.cs:
--------------------------------------------------------------------------------
1 | using BervProject.WebApi.Integration.Test.Fixtures;
2 |
3 | namespace BervProject.WebApi.Integration.Test.Collections
4 | {
5 | [CollectionDefinition("Webapp")]
6 | public class WebAppCollection : ICollectionFixture
7 | {
8 | // This class has no code, and is never created. Its purpose is simply
9 | // to be the place to apply [CollectionDefinition] and all the
10 | // ICollectionFixture<> interfaces.
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Integration.Test/CronControllerTest.cs:
--------------------------------------------------------------------------------
1 | using BervProject.WebApi.Integration.Test.Fixtures;
2 | using Hangfire;
3 | using Microsoft.AspNetCore.Mvc.Testing;
4 |
5 | namespace BervProject.WebApi.Integration.Test
6 | {
7 | [Collection("Webapp")]
8 | public class CronControllerTest : IDisposable
9 | {
10 | private readonly WebApplicationFactory _applicationFactory;
11 | private readonly List _registeredRecurring = new List();
12 | public CronControllerTest(WebAppFixture webAppFixtures)
13 | {
14 | this._applicationFactory = webAppFixtures.WebApp;
15 | }
16 |
17 | public void Dispose()
18 | {
19 | RemoveRecurringJob();
20 | }
21 |
22 | private void RemoveRecurringJob()
23 | {
24 | var cronClient = (IRecurringJobManager?)this._applicationFactory.Services.GetService(typeof(IRecurringJobManager));
25 | if (cronClient != null)
26 | {
27 | foreach (var cronId in _registeredRecurring)
28 | {
29 | cronClient.RemoveIfExists(cronId);
30 | }
31 | }
32 | }
33 |
34 | [Fact]
35 | public async Task SuccessCreateCronOnceTest()
36 | {
37 | var client = _applicationFactory.CreateClient();
38 | var response = await client.PostAsync("/api/v1.0/cron/CreateCronOnce", null);
39 | Assert.True(response.IsSuccessStatusCode);
40 | var stringResponse = await response.Content.ReadAsStringAsync();
41 | Assert.NotEmpty(stringResponse);
42 | var cronClient = (IBackgroundJobClient?)this._applicationFactory.Services.GetService(typeof(IBackgroundJobClient));
43 | if (cronClient != null)
44 | {
45 | var deleted = cronClient.Delete(stringResponse);
46 | Assert.True(deleted);
47 | }
48 | }
49 |
50 | [Fact]
51 | public async Task SuccessCreateRecuranceTest()
52 | {
53 | var client = _applicationFactory.CreateClient();
54 | var response = await client.PostAsync("/api/v1.0/cron/CreateRecurance", null);
55 | Assert.True(response.IsSuccessStatusCode);
56 | var stringResponse = await response.Content.ReadAsStringAsync();
57 | Assert.NotEmpty(stringResponse);
58 | _registeredRecurring.Add(stringResponse);
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/BervProject.WebApi.Integration.Test/Docs/test.txt:
--------------------------------------------------------------------------------
1 | My test file
--------------------------------------------------------------------------------
/BervProject.WebApi.Integration.Test/ErrorControllerTest.cs:
--------------------------------------------------------------------------------
1 | using BervProject.WebApi.Integration.Test.Fixtures;
2 | using Microsoft.AspNetCore.Mvc.Testing;
3 | using Newtonsoft.Json.Linq;
4 |
5 | namespace BervProject.WebApi.Integration.Test
6 | {
7 | [Collection("Webapp")]
8 | public class ErrorControllerTest
9 | {
10 | private readonly WebApplicationFactory _applicationFactory;
11 | public ErrorControllerTest(WebAppFixture webAppFixtures)
12 | {
13 | this._applicationFactory = webAppFixtures.WebApp;
14 | }
15 | [Fact]
16 | public async Task SuccessCheck()
17 | {
18 | var client = _applicationFactory.CreateClient();
19 | var response = await client.GetAsync("/api/v1.0/error/error");
20 | Assert.False(response.IsSuccessStatusCode);
21 | Assert.Equal(System.Net.HttpStatusCode.InternalServerError, response.StatusCode);
22 | var responseString = await response.Content.ReadAsStringAsync();
23 | var jObject = JObject.Parse(responseString);
24 | var status = jObject.Value("status");
25 | var title = jObject.Value("title");
26 | Assert.Equal("An error occurred while processing your request.", title);
27 | Assert.Equal(500, status);
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Integration.Test/Fixtures/WebAppFixture.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc.Testing;
2 |
3 | namespace BervProject.WebApi.Integration.Test.Fixtures
4 | {
5 | public class WebAppFixture : IDisposable
6 | {
7 | public WebAppFixture()
8 | {
9 | WebApp = new WebApplicationFactory()
10 | .WithWebHostBuilder(builder =>
11 | {
12 | // ... Configure test services
13 | });
14 |
15 | }
16 |
17 | public void Dispose() => WebApp.Dispose();
18 |
19 | public WebApplicationFactory WebApp { get; private set; }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Integration.Test/HealthCheckTest.cs:
--------------------------------------------------------------------------------
1 | using BervProject.WebApi.Integration.Test.Fixtures;
2 | using Microsoft.AspNetCore.Mvc.Testing;
3 |
4 | namespace BervProject.WebApi.Integration.Test
5 | {
6 | [Collection("Webapp")]
7 | public class HealthCheckTest
8 | {
9 | private readonly WebApplicationFactory _applicationFactory;
10 | public HealthCheckTest(WebAppFixture webAppFixtures)
11 | {
12 | this._applicationFactory = webAppFixtures.WebApp;
13 | }
14 | [Fact]
15 | public async Task SuccessCheck()
16 | {
17 | var client = _applicationFactory.CreateClient();
18 | var response = await client.GetAsync("/health");
19 | Assert.True(response.IsSuccessStatusCode);
20 | var stringResponse = await response.Content.ReadAsStringAsync();
21 | Assert.Equal("Healthy", stringResponse);
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/BervProject.WebApi.Integration.Test/NoteControllerTest.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Http.Json;
2 | using BervProject.WebApi.Integration.Test.Fixtures;
3 | using BervProject.WebApi.Boilerplate.Entities;
4 | using Microsoft.AspNetCore.Mvc.Testing;
5 |
6 | namespace BervProject.WebApi.Integration.Test
7 | {
8 | [Collection("Webapp")]
9 | public class NoteControllerTest
10 | {
11 | private readonly WebApplicationFactory _applicationFactory;
12 | public NoteControllerTest(WebAppFixture webAppFixtures)
13 | {
14 | this._applicationFactory = webAppFixtures.WebApp;
15 | }
16 | [Fact]
17 | public async Task CreateNoteTest()
18 | {
19 | var client = _applicationFactory.CreateClient();
20 | var response = await client.PostAsync("/api/v1.0/note/createTable", null);
21 | Assert.True(response.IsSuccessStatusCode);
22 | var stringResponse = await response.Content.ReadAsStringAsync();
23 | Assert.Equal("true", stringResponse);
24 | var partitionKey = "part-1";
25 | var rowKey = "row-1";
26 | var title = "Hello World!";
27 | var message = "Yes!";
28 | var newNote = new Note()
29 | {
30 | PartitionKey = partitionKey,
31 | RowKey = rowKey,
32 | Title = title,
33 | Message = message,
34 | };
35 | response = await client.PostAsJsonAsync("/api/v1.0/note/upsert", newNote);
36 | Assert.True(response.IsSuccessStatusCode);
37 | stringResponse = await response.Content.ReadAsStringAsync();
38 | Assert.Equal("true", stringResponse);
39 | response = await client.GetAsync($"/api/v1.0/note/get?partitionKey={partitionKey}&rowKey={rowKey}");
40 | Assert.True(response.IsSuccessStatusCode);
41 | var data = await response.Content.ReadFromJsonAsync();
42 | Assert.NotNull(data);
43 | Assert.Equal(title, data.Title);
44 | Assert.Equal(message, data.Message);
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/BervProject.WebApi.Integration.Test/StorageQueueControllerTest.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Http.Json;
2 | using System.Text;
3 | using System.Text.Json;
4 | using BervProject.WebApi.Boilerplate.Models;
5 | using BervProject.WebApi.Boilerplate.Models.Response;
6 | using BervProject.WebApi.Integration.Test.Fixtures;
7 | using Microsoft.AspNetCore.Mvc.Testing;
8 | using Newtonsoft.Json.Linq;
9 |
10 | namespace BervProject.WebApi.Integration.Test
11 | {
12 | [Collection("Webapp")]
13 | public class StorageQueueControllerTest
14 | {
15 | private readonly WebApplicationFactory _applicationFactory;
16 | public StorageQueueControllerTest(WebAppFixture webAppFixtures)
17 | {
18 | this._applicationFactory = webAppFixtures.WebApp;
19 | }
20 | [Fact]
21 | public async Task StorageQueueSendMessageTest()
22 | {
23 | var client = _applicationFactory.CreateClient();
24 | var messageData = new MessageData{
25 | Message = "Hello World!"
26 | };
27 | using var content = new StringContent(JsonSerializer.Serialize(messageData), Encoding.UTF8, "application/json");
28 | var response = await client.PostAsync("/api/v1.0/storagequeue/sendMessage", content);
29 | Assert.True(response.IsSuccessStatusCode);
30 | var data = await response.Content.ReadFromJsonAsync();
31 | Assert.NotNull(data);
32 | Assert.True(data.IsSuccess);
33 | response = await client.GetAsync("/api/v1.0/storagequeue/receiveMessage");
34 | Assert.True(response.IsSuccessStatusCode);
35 | data = await response.Content.ReadFromJsonAsync();
36 | Assert.NotNull(data);
37 | Assert.True(data.IsSuccess);
38 | Assert.Equal("Hello World!", data.YourMessage);
39 |
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Integration.Test/Usings.cs:
--------------------------------------------------------------------------------
1 | global using Xunit;
--------------------------------------------------------------------------------
/BervProject.WebApi.Integration.Test/WeatherForecastControllerTest.cs:
--------------------------------------------------------------------------------
1 |
2 | using BervProject.WebApi.Boilerplate.Entities;
3 | using BervProject.WebApi.Integration.Test.Fixtures;
4 | using Microsoft.AspNetCore.Mvc.Testing;
5 | using System.Net.Http.Json;
6 |
7 | namespace BervProject.WebApi.Integration.Test
8 | {
9 | [Collection("Webapp")]
10 | public class WeatherForecastControllerTest
11 | {
12 | private readonly WebApplicationFactory _applicationFactory;
13 | public WeatherForecastControllerTest(WebAppFixture webAppFixtures)
14 | {
15 | this._applicationFactory = webAppFixtures.WebApp;
16 | }
17 | [Fact]
18 | public async Task SuccessCheck()
19 | {
20 | var client = _applicationFactory.CreateClient();
21 | var response = await client.GetAsync("/api/v1.0/weatherforecast/db");
22 | Assert.True(response.IsSuccessStatusCode);
23 | var books = await response.Content.ReadFromJsonAsync>();
24 | Assert.NotNull(books);
25 | Assert.Equal(2, books.Count);
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/BervProject.WebApi.Test/BervProject.WebApi.Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | false
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 | runtime; build; native; contentfiles; analyzers; buildtransitive
14 | all
15 |
16 |
17 |
18 |
19 |
20 | runtime; build; native; contentfiles; analyzers; buildtransitive
21 | all
22 |
23 |
24 | runtime; build; native; contentfiles; analyzers; buildtransitive
25 | all
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Test/Services/AWS/AWSS3ServiceTest.cs:
--------------------------------------------------------------------------------
1 | using Amazon.S3;
2 | using Amazon.S3.Model;
3 | using Autofac.Extras.Moq;
4 | using BervProject.WebApi.Boilerplate.Services.AWS;
5 | using Microsoft.AspNetCore.Http;
6 | using Moq;
7 | using System.IO;
8 | using System.Threading.Tasks;
9 | using Xunit;
10 |
11 | namespace BervProject.WebApi.Test.Services.AWS
12 | {
13 | public class AWSS3ServiceTest
14 | {
15 |
16 | [Fact]
17 | public async Task UploadFileSuccess()
18 | {
19 | using var mock = AutoMock.GetLoose();
20 | var amazonS3Mock = mock.Mock();
21 | var fileMock = mock.Mock();
22 | var nullStream = new MemoryStream(0);
23 | var fileName = "ok.jpg";
24 | var contentType = "image/jpeg";
25 | amazonS3Mock.Setup(x => x.PutObjectAsync(It.IsAny(), default));
26 | fileMock.SetupGet(x => x.FileName).Returns(fileName);
27 | fileMock.SetupGet(x => x.ContentType).Returns(contentType);
28 | fileMock.Setup(x => x.OpenReadStream()).Returns(nullStream);
29 | var awsS3Service = mock.Create();
30 | var result = await awsS3Service.UploadFile(fileMock.Object);
31 | Assert.Equal($"uploads/{fileName}", result);
32 | fileMock.Verify(x => x.OpenReadStream(), Times.Once());
33 | amazonS3Mock.Verify(x => x.PutObjectAsync(It.IsAny(), default), Times.Once());
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Test/Services/AWS/DynamoDbServicesTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using Amazon.DynamoDBv2;
4 | using Amazon.DynamoDBv2.Model;
5 | using Autofac.Extras.Moq;
6 | using BervProject.WebApi.Boilerplate.Services.AWS;
7 | using Microsoft.Extensions.Logging;
8 | using Moq;
9 | using Xunit;
10 |
11 | namespace BervProject.WebApi.Test.Services.AWS
12 | {
13 | public class DynamoDbServicesTest
14 | {
15 | [Fact]
16 | public async Task Test_CreateObject()
17 | {
18 | using var mock = AutoMock.GetLoose();
19 | var amazonDynamoDBMock = mock.Mock();
20 | var logMock = mock.Mock>();
21 | amazonDynamoDBMock.Setup(x => x.PutItemAsync(It.IsAny(), default))
22 | .Returns(Task.FromResult(new PutItemResponse
23 | {
24 | HttpStatusCode = System.Net.HttpStatusCode.OK,
25 | Attributes = new System.Collections.Generic.Dictionary
26 | {
27 | {"mock", new AttributeValue ("Hello")}
28 | }
29 | }));
30 | var dynamoDbServices = mock.Create();
31 | await dynamoDbServices.CreateObject();
32 | amazonDynamoDBMock.Verify(x => x.PutItemAsync(It.IsAny(), default), Times.Once());
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/BervProject.WebApi.Test/Services/AWS/EmailServiceTest.cs:
--------------------------------------------------------------------------------
1 | using Amazon.SimpleEmail;
2 | using Amazon.SimpleEmail.Model;
3 | using Autofac.Extras.Moq;
4 | using BervProject.WebApi.Boilerplate.Services.AWS;
5 | using Microsoft.Extensions.Logging;
6 | using Moq;
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Threading.Tasks;
10 | using Xunit;
11 |
12 | namespace BervProject.WebApi.Test.Services.AWS
13 | {
14 | public class EmailServiceTest
15 | {
16 | [Fact]
17 | public async Task SendEmailSuccess()
18 | {
19 | using var mock = AutoMock.GetLoose();
20 | var mockEmailService = mock.Mock();
21 | var logMock = mock.Mock>();
22 | var reciever = new List
23 | {
24 | "myreceiver@receiver.com"
25 | };
26 | var sendEmailResponse = new SendEmailResponse()
27 | {
28 | HttpStatusCode = System.Net.HttpStatusCode.OK,
29 | MessageId = "random",
30 | ResponseMetadata = new Amazon.Runtime.ResponseMetadata()
31 | };
32 | mockEmailService.Setup(x => x.SendEmailAsync(It.IsAny(), default))
33 | .Returns(Task.FromResult(sendEmailResponse));
34 | var emailService = mock.Create();
35 | await emailService.SendEmail(reciever);
36 | mockEmailService.Verify(x => x.SendEmailAsync(It.IsAny(), default), Times.Once());
37 | }
38 |
39 | [Fact]
40 | public async Task SendEmailFailed()
41 | {
42 | using var mock = AutoMock.GetLoose();
43 | var mockEmailService = mock.Mock();
44 | var logMock = mock.Mock>();
45 | var reciever = new List
46 | {
47 | "myreceiver@receiver.com"
48 | };
49 | var sendEmailResponse = new SendEmailResponse()
50 | {
51 | HttpStatusCode = System.Net.HttpStatusCode.InternalServerError,
52 | MessageId = "random",
53 | ResponseMetadata = new Amazon.Runtime.ResponseMetadata()
54 | };
55 | mockEmailService.Setup(x => x.SendEmailAsync(It.IsAny(), default))
56 | .Returns(Task.FromResult(sendEmailResponse));
57 | var emailService = mock.Create();
58 | await emailService.SendEmail(reciever);
59 | mockEmailService.Verify(x => x.SendEmailAsync(It.IsAny(), default), Times.Once());
60 | logMock.Verify(l =>
61 | l.Log(
62 | LogLevel.Warning,
63 | It.IsAny(),
64 | It.Is((state, type) => state.ToString().Equals("There is a problem when sending email")),
65 | null,
66 | (Func